# Introduction Source: https://developer.opus.com/api-reference/introduction Programmatically generate workflows, upload files, run cases, and retrieve results with the Opus API ## Overview The Opus API allows external applications to programmatically generate workflows, run them as **cases**, and monitor and retrieve their results — entirely through the API. The API supports a full range of data inputs, including: * Text and numbers * Booleans and dates * Objects and lists * Single and multiple file uploads (max **10 MB** per file) ## Base URL All API requests should be made to the following base URL: ``` https://operator.opus.com/api/v1 ``` ## Authentication All API endpoints require authentication using the `x-service-key` header. ``` x-service-key: ``` Your API key is a unique, secret credential. Store it securely and never expose it in client-side code. ## Case Execution Flow The typical flow for running a workflow through the API follows these steps: Retrieve the workflow's input schema using `GET /workflow/{workflowId}` to understand what inputs are required. No workflow yet? [Generate one from a prompt](/api-reference/v1-workflow-generation/generate-headless). Create a new case using `POST /case` and receive a `caseId`. If your workflow requires file inputs, upload them using `POST /file/upload/presigned` and the presigned URL flow. Run the case with your populated inputs using `POST /case/{caseId}/execute`. Optionally pass a `callbackUrl` to be notified when the run finishes. Check the case's progress using `GET /case/{caseId}/status` — or skip polling and wait for your callback. Once completed, fetch the results using `GET /case/{caseId}/results`. ## Available Endpoints Create a workflow from a natural-language prompt Retrieve workflow schema and input requirements Create a new case for a workflow Upload files for case inputs Run a case with populated inputs Check case execution progress Retrieve completed case outputs Access per-node execution records # API Quickstart Source: https://developer.opus.com/api-reference/quickstart Get started with the Opus API Before running your first case programmatically on the Opus platform, you need to ensure the following prerequisites are in place. ## Authentication & Base URL All API requests must be made to the following base URL and include the `x-service-key` header for authentication. * **Base URL:** `https://operator.opus.com/api/v1` * **Authentication Header:** `x-service-key: ` ## Obtaining Your API Key The `x-service-key` is your unique, secret API key for authenticating your requests. Follow these steps to generate one: Open the Opus platform, and login to an account that has access to API Key. Click the **Opus button** on the top left of your screen, you will find **API** under the **Channels** section. Click the **+ Generate API Key** button. A modal will appear. You need choose a unique **Key Name** for your reference, and set the **Key Expiry**. Click the **Generate** button. Your new `x-service-key` will be displayed. **This is the only time the key will be shown.** You must copy this key immediately and store it in a secure location. After creation, your key will be listed in the **API** page, under the **Channels** section. Here you can see its name, creation date, expiration date, last used date, and an option to **Delete** the key. ## Finding Your Workflow ID The `workflow_id` is the unique identifier for the specific workflow you want to trigger. This ID is found in the URL of your Opus environment. You can find this ID in two common places: Navigate to the **Workflows** tab in your Opus application, find your workflow, and click on it. The URL in your browser will show the ID. Open your workflow in the Builder. The URL in your browser will also contain the ID. In both cases, the URL will follow this pattern: ``` app.opus.com/app/workflow/{workflowId} ``` For example, in the URL `app.opus.com/app/workflow/9a0af3e5-dc8d-4d19-931d-34c1eeaca233`, the Workflow ID is `9a0af3e5-dc8d-4d19-931d-34c1eeaca233`. Workflow IDs are UUIDs. ## Next Steps Once you have your API key and workflow ID, you're ready to start using the API: Retrieve the input requirements for your workflow Create a new case for your workflow # Execute Job Source: https://developer.opus.com/api-reference/v0-jobs/execute-job POST https://operator.opus.com/job/execute Run a workflow with populated inputs This is the primary step where you provide all inputs and run the workflow. The request body consists of: * The `jobExecutionId` from the [Initiate Job](/api-reference/v0-jobs/initiate-job) step * The `jobPayloadSchemaInstance` — the schema from [Get Workflow Details](/api-reference/v0-jobs/get-workflow-details) with values populated for each input * A `callbackUrl` that Opus will POST to when the job finishes Job execution is asynchronous. This endpoint returns immediately once the run is queued; the final result is delivered to your `callbackUrl` (and is also retrievable via [Get Job Results](/api-reference/jobs/get-job-results)). ## Headers Your API authentication key ## Body Parameters The ID of the job to execute (received from Initiate Job) An object where each key is a variable name from your workflow schema, and each value is a Variable Object (see below). HTTPS URL that Opus will POST the job result to once the run finishes. Must be reachable from the Opus platform. Optional comma-separated workspace IDs used to validate workflow access. Used by machine-key callers that operate across multiple workspaces. ### Variable Object Each entry in `jobPayloadSchemaInstance` uses your variable name as the key (e.g., `VARIABLE_NAME_1`) and maps to an object with the following properties: The value for this input (type depends on field type) The data type: str, float, bool, date, file, array, array\_files, or object The variable name displayed in the Opus platform UI While `displayName` is optional, omitting it may cause display glitches on the Opus platform UI. We strongly recommend including it for each input field. ## Response Whether the job execution was successfully started The job execution ID Status message ```bash cURL theme={null} curl --request POST \ --url https://operator.opus.com/job/execute \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "jobExecutionId": "{YOUR_JOB_EXECUTION_ID}", "callbackUrl": "https://your-app.example.com/opus/callback", "jobPayloadSchemaInstance": { "{VARIABLE_NAME_1}": { "value": "API Test Project", "type": "str", "displayName": "Variable Name 1" }, "{VARIABLE_NAME_2}": { "value": 45.8, "type": "float", "displayName": "Variable Name 2" } } }' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/job/execute" headers = { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}" } payload = { "jobExecutionId": "{YOUR_JOB_EXECUTION_ID}", "callbackUrl": "https://your-app.example.com/opus/callback", "jobPayloadSchemaInstance": { "{VARIABLE_NAME_1}": { "value": "API Test Project", "type": "str", "displayName": "Variable Name 1" }, "{VARIABLE_NAME_2}": { "value": 45.8, "type": "float", "displayName": "Variable Name 2" } } } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const response = await fetch("https://operator.opus.com/job/execute", { method: "POST", headers: { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}", }, body: JSON.stringify({ jobExecutionId: "{YOUR_JOB_EXECUTION_ID}", callbackUrl: "https://your-app.example.com/opus/callback", jobPayloadSchemaInstance: { "{VARIABLE_NAME_1}": { value: "API Test Project", type: "str", displayName: "Variable Name 1", }, "{VARIABLE_NAME_2}": { value: 45.8, type: "float", displayName: "Variable Name 2", }, }, }), }); const data = await response.json(); console.log(data); ``` ```json 201 Response theme={null} { "success": true, "jobExecutionId": "{JOB_EXECUTION_ID}", "message": "Job execution has been started" } ``` # Get Job Execution Results Source: https://developer.opus.com/api-reference/v0-jobs/get-job-results GET https://operator.opus.com/job/{jobExecutionId}/results Retrieve the output and results of a completed job Once the status of a job is `COMPLETED`, you can use this endpoint to retrieve the results of the job execution. The response contains a single top-level field, `jobResultsPayloadSchema`, whose keys are the output variable names defined by your workflow. This endpoint should only be called after the job status returns `COMPLETED`. Check the status first using [Get Job Status](/api-reference/v0-jobs/get-job-status). ## Path Parameters The ID of the job whose execution results you want to retrieve. This is the `jobExecutionId` returned from [Initiate Job](/api-reference/v0-jobs/initiate-job). ## Headers Your API authentication key ## Response The workflow's output payload, keyed by output variable name. Each entry is a Variable Object whose shape mirrors the inputs you provided in [Execute Job](/api-reference/v0-jobs/execute-job). The output value. Its concrete type depends on `type` (e.g., a string for `str`, a URL for `file`, an array for `array`). The data type of the output: `str`, `float`, `bool`, `date`, `file`, `array`, `array_files`, or `object`. The variable name displayed in the Opus platform UI. The keys inside `jobResultsPayloadSchema` are defined by your workflow's output schema and will vary between workflows. The example below is illustrative — your output variable names will differ. ```bash cURL theme={null} curl --request GET \ --url https://operator.opus.com/job/{YOUR_JOB_EXECUTION_ID}/results \ --header 'x-service-key: {YOUR_SERVICE_KEY}' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/job/{YOUR_JOB_EXECUTION_ID}/results" headers = {"x-service-key": "{YOUR_SERVICE_KEY}"} response = requests.get(url, headers=headers) results = response.json() # Iterate over each output variable defined by your workflow for name, variable in results["jobResultsPayloadSchema"].items(): print(f"{name} ({variable['type']}): {variable['value']}") ``` ```javascript JavaScript theme={null} const response = await fetch( "https://operator.opus.com/job/{YOUR_JOB_EXECUTION_ID}/results", { method: "GET", headers: { "x-service-key": "{YOUR_SERVICE_KEY}", }, } ); const results = await response.json(); // Iterate over each output variable defined by your workflow for (const [name, variable] of Object.entries(results.jobResultsPayloadSchema)) { console.log(`${name} (${variable.type}): ${variable.value}`); } ``` ```json 200 Response theme={null} { "jobResultsPayloadSchema": { "{OUTPUT_VARIABLE_1}": { "value": "{STRING_VALUE}", "type": "str", "displayName": "Summary" }, "{OUTPUT_VARIABLE_2}": { "value": "{FILE_URL}", "type": "file", "displayName": "Generated Report" } } } ``` # Get Job Execution Status Source: https://developer.opus.com/api-reference/v0-jobs/get-job-status GET https://operator.opus.com/job/{jobExecutionId}/status Check the current status of a job execution After executing a job, you can use this endpoint to check its status. The job can be in one of several states as it progresses through execution. ## Path Parameters The ID of the job whose execution status you want to check ## Headers Your API authentication key ## Response The current status of the job execution ## Status Values | Status | Description | | - | - | | `IN PROGRESS` | The job is currently being executed | | `COMPLETED` | The job has finished successfully | | `FAILED` | The job encountered an error and could not complete | Poll this endpoint periodically to monitor job progress. Once the status is `COMPLETED`, you can retrieve the results using the [Get Job Results](/api-reference/v0-jobs/get-job-results) endpoint. ```bash cURL theme={null} curl --request GET \ --url https://operator.opus.com/job/{YOUR_JOB_EXECUTION_ID}/status \ --header 'x-service-key: {YOUR_SERVICE_KEY}' ``` ```python Python theme={null} import requests import time url = "https://operator.opus.com/job/{YOUR_JOB_EXECUTION_ID}/status" headers = {"x-service-key": "{YOUR_SERVICE_KEY}"} # Poll until completion while True: response = requests.get(url, headers=headers) data = response.json() print(f"Status: {data['status']}") if data["status"] in ["COMPLETED", "FAILED"]: break time.sleep(5) # Wait 5 seconds before polling again ``` ```javascript JavaScript theme={null} const checkStatus = async () => { const response = await fetch( "https://operator.opus.com/job/{YOUR_JOB_EXECUTION_ID}/status", { method: "GET", headers: { "x-service-key": "{YOUR_SERVICE_KEY}", }, } ); const data = await response.json(); console.log(`Status: ${data.status}`); return data.status; }; // Poll until completion const pollStatus = async () => { let status = await checkStatus(); while (status === "IN PROGRESS") { await new Promise((resolve) => setTimeout(resolve, 5000)); status = await checkStatus(); } return status; }; ``` ```json 200 Response - In Progress theme={null} { "status": "IN PROGRESS" } ``` ```json 200 Response - Completed theme={null} { "status": "COMPLETED" } ``` ```json 200 Response - Failed theme={null} { "status": "FAILED" } ``` # Get Upload URL Source: https://developer.opus.com/api-reference/v0-jobs/get-upload-url POST https://operator.opus.com/job/file/upload Generate a presigned URL for uploading files to use as job inputs If your workflow contains file inputs (type: `file` or `array_files`), you must upload files before executing the job. This endpoint generates a presigned URL for uploading. Call this endpoint once for **each file** you need to upload. After receiving the presigned URL, proceed to [Upload File](/api-reference/v0-jobs/upload-file) to complete the upload. ## Headers Your API authentication key ## Body Parameters The file extension including the dot (e.g., `.pdf`, `.docx`) Access scope for the file. Options: `all`, `user`, `workspace`, `organization`. If omitted, the file is uploaded as **unlisted** — tracked by the platform but not shown in the file library. The original filename of the file being uploaded (e.g., `Q4-Report.pdf`). Surfaced in the Opus file library to make the file easier to identify later. Target workspace ID for the file. Required when `accessScope` is `workspace` and `workflowId` is not provided. Target workflow ID for the file. The workspace that owns this workflow becomes the owner of the file. Required when `accessScope` is `workspace` and `workspaceId` is not provided. ## Supported File Types | Extension | Description | | - | - | | `.pdf` | PDF documents | | `.docx` | Word documents | | `.csv` | CSV spreadsheets | | `.xls`, `.xlsx` | Excel spreadsheets | | `.txt` | Plain text files | | `.json` | JSON files | | `.html` | HTML files | | `.xml` | XML files | | `.jpeg`, `.jpg`, `.png` | Image files | The maximum file size for uploads is **10 MB**. Files exceeding this limit will be rejected. ## Response Temporary URL for uploading your file. Use this in the [Upload File](/api-reference/v0-jobs/upload-file) step. Permanent URL to reference this file in your [Execute Job](/api-reference/v0-jobs/execute-job) request. ```bash cURL theme={null} curl --request POST \ --url https://operator.opus.com/job/file/upload \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "fileExtension": ".pdf", "originalName": "Q4-Report.pdf", "accessScope": "organization" }' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/job/file/upload" headers = { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}" } payload = { "fileExtension": ".pdf", "originalName": "Q4-Report.pdf", "accessScope": "organization" } response = requests.post(url, json=payload, headers=headers) data = response.json() print(data) ``` ```javascript JavaScript theme={null} const response = await fetch("https://operator.opus.com/job/file/upload", { method: "POST", headers: { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}", }, body: JSON.stringify({ fileExtension: ".pdf", originalName: "Q4-Report.pdf", accessScope: "organization", }), }); const data = await response.json(); console.log(data); ``` ```json 201 Response theme={null} { "presignedUrl": "{PRESIGNED_URL}", "fileUrl": "{FILE_URL}" } ``` # Get Workflow Details Source: https://developer.opus.com/api-reference/v0-jobs/get-workflow-details GET https://operator.opus.com/workflow/{workflowId} Retrieve the complete schema and input requirements for a workflow Before you can execute a job, you must know what inputs it expects. This endpoint returns the workflow object, including its name, description, blueprint, and the `jobPayloadSchema` that defines all of the workflow's inputs. By default, the response describes the latest active version of the workflow. To inspect a specific historical version, pass either the `version` number or the `workflowVersionId` UUID as a query parameter. ## Path Parameters The unique identifier of the workflow to retrieve details for ## Query Parameters Workflow version number to retrieve. Omit to use the latest active version. Specific workflow version UUID. Takes precedence over `version` when both are supplied. ## Headers Your API authentication key ## Response The `jobPayloadSchema` object defines all workflow inputs, their unique variable names (e.g., `workflow_input_we4tej0ly`), and their data types. An object containing all workflow input definitions Unique identifier for the input field The variable name to use when executing the job Human-readable name for the input Data type: `str`, `float`, `bool`, `date`, `file`, `array`, `array_files`, or `object` Whether the input can be null Additional metadata, such as allowed file types for file inputs ## Supported Data Types | Type | Description | Example Value | | - | - | - | | `str` | Text string | `"Hello World"` | | `float` | Numeric value | `45.8` | | `bool` | Boolean | `true` or `false` | | `date` | Date string | `"2025-11-09"` | | `file` | Single file URL | `"https://files.opus.com/..."` | | `array` | List of values | `["item1", "item2"]` | | `array_files` | Multiple file URLs | `["url1", "url2"]` | | `object` | Nested object | `{"key": "value"}` | ```bash cURL theme={null} # Latest active version curl --request GET \ --url https://operator.opus.com/workflow/{YOUR_WORKFLOW_ID} \ --header 'x-service-key: {YOUR_SERVICE_KEY}' # Pinned to a specific version number curl --request GET \ --url 'https://operator.opus.com/workflow/{YOUR_WORKFLOW_ID}?version=3' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' # Pinned to a specific version UUID curl --request GET \ --url 'https://operator.opus.com/workflow/{YOUR_WORKFLOW_ID}?workflowVersionId={WORKFLOW_VERSION_ID}' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/workflow/{YOUR_WORKFLOW_ID}" headers = {"x-service-key": "{YOUR_SERVICE_KEY}"} # Latest active version response = requests.get(url, headers=headers) # Or pin to a specific version # response = requests.get(url, headers=headers, params={"version": 3}) # response = requests.get(url, headers=headers, params={"workflowVersionId": "{WORKFLOW_VERSION_ID}"}) print(response.json()) ``` ```javascript JavaScript theme={null} // Latest active version const response = await fetch( "https://operator.opus.com/workflow/{YOUR_WORKFLOW_ID}", { method: "GET", headers: { "x-service-key": "{YOUR_SERVICE_KEY}", }, } ); // Or pin to a specific version // const url = new URL("https://operator.opus.com/workflow/{YOUR_WORKFLOW_ID}"); // url.searchParams.set("version", "3"); // const response = await fetch(url, { headers: { "x-service-key": "{YOUR_SERVICE_KEY}" } }); const data = await response.json(); console.log(data); ``` ```json 200 Response theme={null} { "jobPayloadSchema": { "{VARIABLE_NAME_1}": { "id": "{INPUT_ID}", "variable_name": "{VARIABLE_NAME_1}", "display_name": "{DISPLAY_NAME}", "type": "str", "is_nullable": false }, "{VARIABLE_NAME_2}": { "id": "{INPUT_ID}", "variable_name": "{VARIABLE_NAME_2}", "display_name": "{DISPLAY_NAME}", "type": "file", "is_nullable": false, "tags": [ { "variable_name": "allowed_file_types", "value": ["JPEG", "PNG", "JPG", "PDF", "DOCX", "CSV", "XLSX"] } ] } } } ``` # Initiate Job Source: https://developer.opus.com/api-reference/v0-jobs/initiate-job POST https://operator.opus.com/job/initiate Create a new job instance and receive a jobExecutionId This step creates a job instance in the system and returns the unique `jobExecutionId` required for execution and monitoring. You can identify the workflow with either `workflowId` or `referenceEntityId` (a workflow reference entity UUID). If both are sent, `referenceEntityId` takes precedence. The job runs against the latest active version of the workflow unless you pin one with `workflowVersionId` or `workflowVersionNumber`. You must save the `jobExecutionId` returned by this endpoint for all subsequent steps. ## Headers Your API authentication key ## Body Parameters The ID of the workflow to be used for your job. Required unless `referenceEntityId` is provided. The platform resolves it to a workflow reference entity via lookup. Workflow reference entity UUID. Required unless `workflowId` is provided. Takes precedence over `workflowId` if both are sent. Pin the job to a specific workflow version by UUID. Omit to run the latest active version. Pin the job to a specific workflow version by version number. Omit to run the latest active version. Job title shown in the Opus UI Job description shown in the Opus UI The ID of the user who initiated the job. Useful for attributing API-triggered jobs back to a specific end user. Where the job was triggered from. Defaults to `api` for service-key callers. Allowed values: `email-agent`, `chat-agent`, `scheduled`, `api`, `manual`, `agent`, `opus-ai`, `web-app`. Optional comma-separated workspace IDs used to validate workflow access. Used by machine-key callers that operate across multiple workspaces. Initial user-provided inputs to store on the job at creation time. Accepts arbitrary key/value pairs that match your workflow's input schema. The ID of the web app that initiated this job, when the job is launched from a published Opus web app. ## Response The unique identifier for this job execution. Use this ID in all subsequent API calls. ```bash cURL theme={null} # Latest active version (minimal) curl --request POST \ --url https://operator.opus.com/job/initiate \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "workflowId": "{YOUR_WORKFLOW_ID}", "title": "Q4 Report Processing", "description": "Processing quarterly financial reports", "source": "api", "initialInput": { "quarter": "Q4", "fiscalYear": 2025 } }' # Pinned to a specific version number, with attribution + workspace scoping curl --request POST \ --url https://operator.opus.com/job/initiate \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "workflowId": "{YOUR_WORKFLOW_ID}", "workflowVersionNumber": 3, "title": "Q4 Report Processing", "description": "Processing quarterly financial reports", "source": "api", "refUserId": "{END_USER_ID}", "workspaces": "{WORKSPACE_ID_1},{WORKSPACE_ID_2}", "initialInput": { "quarter": "Q4", "fiscalYear": 2025 } }' # Pinned to a specific version UUID, identified by referenceEntityId instead of workflowId curl --request POST \ --url https://operator.opus.com/job/initiate \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "referenceEntityId": "{REFERENCE_ENTITY_ID}", "workflowVersionId": "{WORKFLOW_VERSION_ID}", "title": "Q4 Report Processing", "source": "api" }' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/job/initiate" headers = { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}" } payload = { "workflowId": "{YOUR_WORKFLOW_ID}", # Or identify the workflow by its reference entity instead: # "referenceEntityId": "{REFERENCE_ENTITY_ID}", # Pin a specific workflow version (omit both to use the latest active version): "workflowVersionNumber": 3, # "workflowVersionId": "{WORKFLOW_VERSION_ID}", "title": "Q4 Report Processing", "description": "Processing quarterly financial reports", "source": "api", "refUserId": "{END_USER_ID}", "workspaces": "{WORKSPACE_ID_1},{WORKSPACE_ID_2}", "initialInput": { "quarter": "Q4", "fiscalYear": 2025 } } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const response = await fetch("https://operator.opus.com/job/initiate", { method: "POST", headers: { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}", }, body: JSON.stringify({ workflowId: "{YOUR_WORKFLOW_ID}", // Or identify the workflow by its reference entity instead: // referenceEntityId: "{REFERENCE_ENTITY_ID}", // Pin a specific workflow version (omit both to use the latest active version): workflowVersionNumber: 3, // workflowVersionId: "{WORKFLOW_VERSION_ID}", title: "Q4 Report Processing", description: "Processing quarterly financial reports", source: "api", refUserId: "{END_USER_ID}", workspaces: "{WORKSPACE_ID_1},{WORKSPACE_ID_2}", initialInput: { quarter: "Q4", fiscalYear: 2025, }, }), }); const data = await response.json(); console.log(data); ``` ```json 201 Response theme={null} { "jobExecutionId": "{JOB_EXECUTION_ID}" } ``` # Job Audit Log Source: https://developer.opus.com/api-reference/v0-jobs/job-audit-log GET https://operator.opus.com/job/{jobExecutionId}/audit Retrieve node-by-node execution data for a job Opus exposes a node-level audit for every job. The response shows you which nodes have run, which is running now, which are still queued, and which have failed — together with the per-node execution data that the workflow engine produced. Use it for debugging, compliance, or building progress visualisations on top of a running job. ## Path Parameters The ID of the job whose audit log you want to retrieve ## Headers Your API authentication key ## Response Total number of nodes in the workflow. IDs of nodes that have already finished executing, in the order they ran. Number of nodes that have finished executing. Equal to `executed_nodes.length`. ID of the node currently executing. Empty string when no node is actively running (for example, between nodes or after the job finishes). ID of the node scheduled to run next. Empty string when the job has no more nodes queued. IDs of nodes that are still pending execution. IDs of nodes that failed during execution. Number of failed nodes. Equal to `failed_nodes.length`. Per-node execution data captured by the engine. Map keyed by node ID. Each value contains the inputs, outputs, and runtime metadata captured when that node executed. The exact shape varies by node type. ```bash cURL theme={null} curl --request GET \ --url https://operator.opus.com/job/{YOUR_JOB_EXECUTION_ID}/audit \ --header 'x-service-key: {YOUR_SERVICE_KEY}' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/job/{YOUR_JOB_EXECUTION_ID}/audit" headers = {"x-service-key": "{YOUR_SERVICE_KEY}"} response = requests.get(url, headers=headers) audit = response.json() print(f"Progress: {audit['nb_executed_nodes']}/{audit['nb_nodes']} nodes") print(f"Running: {audit['running_node'] or '(none)'}") print(f"Failed: {audit['nb_failed_nodes']} -> {audit['failed_nodes']}") for node_id, data in audit['audit']['nodes_execution_data'].items(): print(f"\nNode {node_id}:") print(data) ``` ```javascript JavaScript theme={null} const response = await fetch( "https://operator.opus.com/job/{YOUR_JOB_EXECUTION_ID}/audit", { method: "GET", headers: { "x-service-key": "{YOUR_SERVICE_KEY}", }, } ); const audit = await response.json(); console.log(`Progress: ${audit.nb_executed_nodes}/${audit.nb_nodes} nodes`); console.log(`Running: ${audit.running_node || "(none)"}`); console.log(`Failed: ${audit.nb_failed_nodes} -> ${audit.failed_nodes}`); for (const [nodeId, data] of Object.entries(audit.audit.nodes_execution_data)) { console.log(`\nNode ${nodeId}:`, data); } ``` ```json 200 Response theme={null} { "nb_nodes": 5, "executed_nodes": ["{NODE_ID_1}", "{NODE_ID_2}"], "nb_executed_nodes": 2, "running_node": "{NODE_ID_3}", "next_node_to_execute": "{NODE_ID_4}", "remaining_nodes_to_execute": ["{NODE_ID_4}", "{NODE_ID_5}"], "failed_nodes": [], "nb_failed_nodes": 0, "audit": { "nodes_execution_data": { "{NODE_ID_1}": { "{KEY}": "{VALUE}" }, "{NODE_ID_2}": { "{KEY}": "{VALUE}" } } } } ``` # Postman Collection Source: https://developer.opus.com/api-reference/v0-jobs/postman-collection Pre-built API request templates to get started quickly To help you get started quickly, we provide a Postman Collection with pre-configured API requests for all Opus Job Operator endpoints. ## Download Collection Get the complete collection with all API endpoints ## Setup Instructions Open Postman and import the downloaded collection file. Create a Postman environment or collection variable named `base_url` and set it to: ``` https://operator.opus.com ``` Include your API key in the Headers tab of each request: ``` x-service-key: ``` Alternatively, configure it as a collection-level variable for reuse across all requests. Update the following template values with your actual identifiers: * `put_your_workflow_id_here` → Your actual workflow ID * `put_your_job_id_here` → Your actual job execution ID ## Included Requests The collection contains pre-configured requests for: | Endpoint | Method | Description | | - | - | - | | Get Workflow Details | GET | Retrieve workflow schema and input requirements | | Initiate Job | POST | Create a new job instance | | Upload File | POST | Generate presigned file upload URL | | Execute Job | POST | Run workflow with inputs | | Get Job Status | GET | Check execution progress | | Get Job Results | GET | Retrieve completed job outputs | | Job Audit Log | GET | Access execution history | # Upload File Source: https://developer.opus.com/api-reference/v0-jobs/upload-file PUT {presignedUrl} Upload your file to the presigned URL from Get Upload URL Upload your file's binary content to the `presignedUrl` received from [Get Upload URL](/api-reference/v0-jobs/get-upload-url). This request goes to **AWS S3**, not the Opus API. Do not include the `x-service-key` header. ## Headers MIME type matching your file (e.g., `application/pdf`, `image/png`, `text/csv`) ## Body Raw binary data of your file. The maximum file size for uploads is **10 MB**. Requests with files exceeding this limit will be rejected. ## Response Returns HTTP `200` on success with an empty body. ```bash cURL theme={null} curl --request PUT \ --url "{PRESIGNED_URL}" \ --header 'Content-Type: application/pdf' \ --data-binary '@/path/to/your/file.pdf' ``` ```python Python theme={null} import requests presigned_url = "{PRESIGNED_URL}" with open("/path/to/your/file.pdf", "rb") as file: response = requests.put( presigned_url, data=file, headers={"Content-Type": "application/pdf"} ) print(response.status_code) # 200 on success ``` ```javascript JavaScript theme={null} const fs = require("fs"); const presignedUrl = "{PRESIGNED_URL}"; const fileBuffer = fs.readFileSync("/path/to/your/file.pdf"); const response = await fetch(presignedUrl, { method: "PUT", body: fileBuffer, headers: { "Content-Type": "application/pdf", }, }); console.log(response.status); // 200 on success ``` ```text 200 Response theme={null} (empty body) ``` # Introduction Source: https://developer.opus.com/api-reference/v1-agent/agent-introduction Author agents for your organization entirely through the API ## Overview The Agents API lets you register your own agents in the Opus marketplace programmatically — the agent itself, the prompts it runs, and the typed inputs and outputs it exposes to a workflow. These endpoints author the agent **catalog**: the definition of an agent, shared across your whole organization. Connecting an agent into a workspace so a workflow can run it is a separate, workspace-scoped step done in the Opus app. ## Base URL All API requests should be made to the following base URL: ``` https://operator.opus.com/api/v1/agent ``` ## Authentication All API endpoints require authentication with your Opus API key, sent in the `x-service-key` header. ```text theme={null} x-service-key: ``` Your key determines your identity and your organization. Every endpoint here requires the **Agent: Full** permission **at organization level** — a workspace-level grant is not sufficient, because an agent authored here belongs to the organization rather than to a workspace. A request with a missing, invalid, or expired key returns `401`. A key that is not org-scoped, or whose owner lacks **Agent: Full** in the organization, returns `403`. Your API key is a unique, secret credential. Store it securely and never expose it in client-side code. Your organization must be verified to publish to the marketplace. An unverified organization passes validation here and is rejected downstream with `422`. ## Authoring Flow Authoring an agent takes a single call. Unlike the [Integrations API](/api-reference/v1-integration/integration-introduction), there is no provider to create first — your organization's agent provider is created on demand on your first agent. `POST /` registers the agent under your organization with its prompts and IO schema. Keep the returned `id`. `PATCH /{agentId}` updates any subset of fields. Each call cuts a new agent version, so the previous state stays addressable. There is no `providerId` field anywhere in this section. The organization comes from your API key and the agent service resolves that organization's canonical provider itself — accepting one from the caller would allow authoring into another organization's provider. ## Agent Classes An agent is driven either by raw prompts or by a blueprint of ordered steps. **This API authors [Custom Agents](/tasks/agent/custom-agent) only** — `blueprint` carries a `systemPrompt` and a `userPrompt`, and the class is pinned for you. There is no `agentClass` field to set. [Opus Agents](/tasks/agent/opus-agent) — the kind authored inside the Opus app, from an objective, input/process/output descriptions and ordered steps — cannot be created here. They can still be revised through [Update an Agent](/api-reference/v1-agent/update-agent), which accepts either shape. | | Create | Update | | - | - | - | | Custom Agent | Yes | Yes | | Opus Agent | No | Yes | An agent's class is fixed when it is created and cannot be changed afterwards — a blueprint in the wrong shape would leave the agent unable to run. `blueprint` is otherwise forwarded to the agent service untouched and stored verbatim, so **nothing in it beyond the prompts and the model it names is validated structurally**. The documented fields are a base, not a ceiling: extra fields are kept and forwarded. ## Inputs and Outputs `inputs` and `outputs` describe the agent's signature to the workflow builder. Both are maps keyed by the variable's own `variableName`: ```json theme={null} { "firstNumber": { "id": "1", "variableName": "firstNumber", "displayName": "First Number", "allowedTypes": [{ "type": "float" }] } } ``` The key and the `variableName` inside it must match. Each variable needs at least one entry in `allowedTypes`; for composite types, `allowedTypes[].typeDefinition` describes the shape inside. ## Usage Notes * **Nothing is workspace-scoped.** An agent authored here belongs to your organization. No workspace id is accepted anywhere in this section. * **An agent is not runnable on create.** It is a catalog entry until it is connected into a workspace. * **Create authors Custom Agents only.** A blueprint without a non-empty `systemPrompt` and `userPrompt` is rejected with `400`. Either casing is accepted. * **Models are checked before the agent is stored.** Both endpoints reject a blueprint naming a model the platform cannot route to, or a provider that contradicts the model beside it. See [Models and providers](/api-reference/v1-agent/create-agent#models-and-providers). * **Update replaces, it does not merge.** `blueprint`, `inputs` and `outputs` are swapped wholesale by `PATCH`. Send the complete object you want stored. * **`400` is us, `422` is downstream.** A `400` means this API rejected your body. A `422` means it passed validation here and was rejected further down — most often an organization not verified to publish to the marketplace. ## Limits | Field | Limit | | - | - | | `name` | 255 characters | | `description` | 2,048 characters | | `icon` | 65,535 characters | | `categories` | 5 entries | | `blueprint` | 256KB JSON-encoded | | `inputs` / `outputs` | 100 variables, 512KB JSON-encoded | | `allowedTypes` | 1–11 entries per variable | | `tags` / `options` / `nonEditableFields` | 20 entries each | ## Available Endpoints Register an agent with its class, blueprint, and IO schema Revise an agent your organization owns, cutting a new version # Create an Agent Source: https://developer.opus.com/api-reference/v1-agent/create-agent POST https://operator.opus.com/api/v1/agent Register a Custom Agent with its prompts and IO schema Register a [Custom Agent](/tasks/agent/custom-agent) in the marketplace under your organization. The agent is authored at the organization level, so it is not bound to a workspace and is not runnable until it is connected into one. Returns the agent `id`, which you pass to [Update an Agent](/api-reference/v1-agent/update-agent). Requires the **Agent: Full** permission at organization level. Every agent created here is a Custom Agent. There is no `agentClass` field to set — the class is pinned, and `blueprint` must carry the prompts the agent runs with. There is no provider call to make first. Your organization's agent provider is created on demand on your first agent, and `providerId` is not accepted in the body. ## Headers Your API authentication key ## Body Parameters The agent is nested under an `agent` key. The agent to create. Fields below. Agent display name. Maximum 255 characters. Agent icon as a base64-encoded SVG (or PNG) — a plain string, with no `data:` prefix. Maximum 65535 characters. The agent implementation: the prompts the agent runs with, plus the model that runs them. See [Blueprint](#blueprint). Maximum 256KB JSON-encoded. Categories the agent is filed under in the marketplace. Maximum 5 entries. See [Categories](#categories). What the agent does, shown under its name. Maximum 2048 characters. The agent's input schema, keyed by each variable's `variableName`. Maximum 100 entries and 512KB JSON-encoded. See [Variable object](#variable-object). The agent's output schema, keyed by each variable's `variableName`. Same shape and limits as `inputs`. Agent status — `active`, `inactive`, `soon` or `deprecated`. Show the "new" badge on the agent tile. Show the "popular" badge on the agent tile. Show the "beta" badge on the agent tile. Accepted on create but not echoed back in the response. Your organization is always taken from the API key — it cannot be set in the body. Nothing here is workspace-scoped. ## Blueprint The prompts the agent runs with. System prompt the agent runs with. Must be non-empty. User prompt template. Must be non-empty. Reference the agent's inputs with `{{variableName}}`. Model the agent runs on, for example `gpt-4o`. Must be one the platform routes to — see [Models and providers](#models-and-providers). Provider of that model, for example `openai`. Must agree with the model when both are given. Model to fall back to. Validated the same way as `model`. Provider of the fallback model. Validated the same way as `provider`. `systemPrompt` and `userPrompt` may be sent in either camelCase or snake\_case (`system_prompt`, `user_prompt`). A blueprint missing either one, or carrying an empty or whitespace-only value for it, is rejected with `400`. Apart from the prompts and these two pairs, `blueprint` is forwarded untouched and stored verbatim — nothing else in it is validated structurally beyond its encoded size. The fields above are a base, not a ceiling: extra fields are kept, and unrecognised keys are forwarded exactly as they arrived. The documented camelCase keys are renamed to the agent service's snake\_case at the boundary. ### Models and providers `model` and `provider` are checked before the agent is created, and the same rules apply to `backupModel` and `backupProvider`. Both pairs are accepted in either casing (`backup_model`, `backup_provider`). A model is accepted when the platform's model registry knows it, or when its name begins with a prefix belonging to a provider the platform routes to — `gpt-`, `o` followed by a digit, and `chatgpt` for `openai`, `claude` for `anthropic`, `gemini` for `google`. The prefix fallback means a model released before the registry catches up is still accepted, so `claude-opus-9-future` passes while `llama-3-70b-instruct` does not. When both a model and a provider are given, the provider must be the one that model actually runs on — `{ "model": "gpt-4o", "provider": "anthropic" }` is rejected. Each pair is checked only when it names a model or a provider. A blueprint that names neither is accepted as it stands. #### Providers A provider named on its own, with no model beside it, must be one of these. Anything else — `mistral`, say — is rejected. | Provider | Routes to | | - | - | | `openai` | GPT models, called directly | | `anthropic` | Claude models, called directly | | `google` | Gemini models | | `bedrock` | Claude and GPT models through AWS Bedrock, ids prefixed `bedrock/` | | `compass` | GPT models through Compass, ids prefixed `compass/` | | `custom_openai` | Custom OpenAI-compatible endpoints. Not offered in the app's model picker | | `custom_anthropic` | Custom Anthropic-compatible endpoints. Not offered in the app's model picker | #### Commonly used models A sample of the current lineup, not the whole of it — the registry moves with the platform, and this page will lag it. The model picker in the Opus app is the live list. | `model` | `provider` | Shown in the app as | | - | - | - | | `gpt-5.6-terra` | `openai` | GPT 5.6 Terra | | `gpt-5.2` | `openai` | GPT 5.2 | | `gpt-4o` | `openai` | GPT 4o | | `claude-opus-5` | `anthropic` | Claude Opus 5 | | `claude-sonnet-5` | `anthropic` | Claude Sonnet 5 | | `claude-haiku-4-5-20251001` | `anthropic` | Claude Haiku 4.5 | | `gemini-3.5-flash` | `google` | Gemini 3.5 Flash | | `gemini-2.5-pro` | `google` | Gemini 2.5 Pro | | `bedrock/claude-opus-5` | `bedrock` | Claude Opus 5 (Bedrock) | | `compass/gpt-5.1` | `compass` | GPT 5.1 (Compass) | Models reached through Bedrock or Compass carry the provider in the id itself, and the two halves must agree. `{ "model": "bedrock/claude-sonnet-5", "provider": "bedrock" }` is accepted; the same model named bare, as `{ "model": "claude-sonnet-5", "provider": "bedrock" }`, resolves to `anthropic` and is rejected. ## Variable object Each value inside `inputs` and `outputs`. The map key must equal the variable's `variableName`. Stable identifier for the variable, unique within the schema. Maximum 255 characters. Programmatic key. Must equal the key this entry sits under. Maximum 255 characters. Value types this variable accepts. Between 1 and 11 entries. Each has a `type` — one of `int`, `float`, `bool`, `str`, `object`, `file`, `array`, `date`, `binary`, `json_string`, `node` — plus optional `typeDefinition` and `typeDefinitionEnforced`. Human-readable label rendered in the workflow builder. Maximum 255 characters. When omitted, the agent service applies its own default. Description shown next to the variable in the builder. Maximum 2048 characters. Pre-filled default value. Its type must match one of `allowedTypes`. When true, the workflow may leave this variable unset. Annotations the builder uses for grouping and filtering, each `{ variableName, value, description }`. Maximum 20. Enum-style choice list. When non-empty the builder renders a dropdown. Each entry is free-form JSON. Maximum 20. Which of `allowedTypes` is currently active. Must be one of them — consumers fall back to the first entry when unset. Fields the builder locks, preventing the workflow author from changing them — any of `variable_name`, `display_name`, `description`, `is_nullable`, `tags`, `options`, `allowed_types`. Maximum 20. When false, the builder hides the "remove variable" affordance. For composite types, `typeDefinition` describes the shape inside: a nested variable map for `object`, a single nested variable for `array`, or a date format string for `date`. Omit it for scalars. Set `typeDefinitionEnforced` to hold the workflow author to it exactly. ## Categories One to five of: `parsing_and_serialization`, `validation_and_normalization`, `transformation_and_mapping`, `aggregation_and_analysis`, `numerical_computation`, `statistical_computation`, `optimization_and_search`, `text_processing`, `document_and_ocr_processing`, `media_processing`, `control_flow_and_orchestration`, `state_and_caching`, `io_and_storage`, `networking_and_apis`, `security_and_identity`. ## Response The agent id. Pass it as `{agentId}` to [Update an Agent](/api-reference/v1-agent/update-agent). Agent display name. Agent description. Agent icon. Categories the agent is filed under. Agent status. Whether the "new" badge is shown. Whether the "popular" badge is shown. Id of the version this call created. Owning workspace, or `null` when the agent is visible across the marketplace. ## Errors Invalid body — a missing required field, a value over its limit, more than 5 categories, a `blueprint` without a non-empty `systemPrompt` and `userPrompt`, a `blueprint` naming a model or provider the platform cannot route to, or an `inputs`/`outputs` entry that is not a valid variable. Missing, invalid, or expired API key. The API key is not org-scoped, or the key owner lacks the **Agent: Full** permission in the organization. Rejected downstream after passing validation here — most often an organization that is not verified to publish to the marketplace. ```bash cURL theme={null} curl --request POST \ --url https://operator.opus.com/api/v1/agent \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "agent": { "name": "Adder", "description": "Adds two numbers and returns the total", "icon": "{BASE64_ICON}", "categories": ["numerical_computation"], "blueprint": { "systemPrompt": "You are a careful arithmetic assistant.", "userPrompt": "Add {{firstNumber}} and {{secondNumber}} and return the total.", "model": "gpt-4o", "provider": "openai" }, "inputs": { "firstNumber": { "id": "1", "variableName": "firstNumber", "displayName": "First Number", "allowedTypes": [{ "type": "float" }] }, "secondNumber": { "id": "2", "variableName": "secondNumber", "displayName": "Second Number", "allowedTypes": [{ "type": "float" }] } }, "outputs": { "sumResult": { "id": "1", "variableName": "sumResult", "displayName": "Sum Result", "allowedTypes": [{ "type": "float" }] } } } }' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/api/v1/agent" headers = { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}" } payload = { "agent": { "name": "Adder", "description": "Adds two numbers and returns the total", "icon": "{BASE64_ICON}", "categories": ["numerical_computation"], "blueprint": { "systemPrompt": "You are a careful arithmetic assistant.", "userPrompt": "Add {{firstNumber}} and {{secondNumber}} and return the total.", "model": "gpt-4o", "provider": "openai", }, "inputs": { "firstNumber": { "id": "1", "variableName": "firstNumber", "displayName": "First Number", "allowedTypes": [{"type": "float"}], }, "secondNumber": { "id": "2", "variableName": "secondNumber", "displayName": "Second Number", "allowedTypes": [{"type": "float"}], }, }, "outputs": { "sumResult": { "id": "1", "variableName": "sumResult", "displayName": "Sum Result", "allowedTypes": [{"type": "float"}], } }, } } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const response = await fetch("https://operator.opus.com/api/v1/agent", { method: "POST", headers: { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}", }, body: JSON.stringify({ agent: { name: "Adder", description: "Adds two numbers and returns the total", icon: "{BASE64_ICON}", categories: ["numerical_computation"], blueprint: { systemPrompt: "You are a careful arithmetic assistant.", userPrompt: "Add {{firstNumber}} and {{secondNumber}} and return the total.", model: "gpt-4o", provider: "openai", }, inputs: { firstNumber: { id: "1", variableName: "firstNumber", displayName: "First Number", allowedTypes: [{ type: "float" }], }, secondNumber: { id: "2", variableName: "secondNumber", displayName: "Second Number", allowedTypes: [{ type: "float" }], }, }, outputs: { sumResult: { id: "1", variableName: "sumResult", displayName: "Sum Result", allowedTypes: [{ type: "float" }], }, }, }, }), }); const data = await response.json(); console.log(data); ``` ```json 201 Response theme={null} { "id": "{AGENT_ID}", "name": "Adder", "description": "Adds two numbers and returns the total", "icon": "{BASE64_ICON}", "categories": ["numerical_computation"], "status": "active", "isNew": true, "isPopular": false, "versionId": "{AGENT_VERSION_ID}", "groupId": null } ``` # Update an Agent Source: https://developer.opus.com/api-reference/v1-agent/update-agent PATCH https://operator.opus.com/api/v1/agent/{agentId} Revise an agent your organization owns, cutting a new version Revise an agent your organization owns. Every field is optional — omitted fields keep their current value. Each call cuts a new agent version rather than editing in place, so the previous state stays addressable. Use the `id` returned by [Create an Agent](/api-reference/v1-agent/create-agent) as `{agentId}`. Requires the **Agent: Full** permission at organization level. `blueprint`, `inputs` and `outputs` are replaced **wholesale**, not merged field by field. Send the complete object you want stored — a partial `inputs` map drops every variable you left out. Unlike create, this endpoint can target either kind of agent: a Custom Agent authored through the API, or an Opus Agent authored in the Opus app. An agent's class is fixed when it is created and cannot be changed here — the `blueprint` you send must match it. See [Blueprint shapes](#blueprint-shapes). ## Headers Your API authentication key ## Path Parameters The agent to revise. This is `id` from [Create an Agent](/api-reference/v1-agent/create-agent) — not its `versionId`. Must be a UUID. ## Body Parameters The agent is nested under an `agent` key. The fields to change. All of them are optional. Agent display name. Maximum 255 characters. What the agent does, shown under its name. Maximum 2048 characters. Agent icon as a base64-encoded SVG (or PNG) — a plain string, with no `data:` prefix. Maximum 65535 characters. Replacement implementation, in the shape matching the agent's class. Replaces the stored blueprint wholesale. Maximum 256KB JSON-encoded. See [Blueprint shapes](#blueprint-shapes). Replacement input schema, keyed by each variable's `variableName`. Same shape and limits as on create — see [Variable object](/api-reference/v1-agent/create-agent#variable-object). Replacement output schema. Same shape and limits as `inputs`. Replacement category list. Maximum 5 entries. See [Categories](/api-reference/v1-agent/create-agent#categories). Agent status — `active`, `inactive`, `soon` or `deprecated`. Show the "new" badge on the agent tile. Show the "popular" badge on the agent tile. Show the "beta" badge on the agent tile. Accepted but not echoed back in the response. ## Blueprint shapes `blueprint` takes one of two shapes, depending on the class of the agent you are updating. Whichever shape you send, its `model`/`provider` pair and its `backupModel`/`backupProvider` pair are validated exactly as they are on create — see [Models and providers](/api-reference/v1-agent/create-agent#models-and-providers). ### Custom Agents Every agent created through [Create an Agent](/api-reference/v1-agent/create-agent) is a [Custom Agent](/tasks/agent/custom-agent) — a model driven by a system prompt and a prompt. Send the same shape that endpoint takes, see [Blueprint](/api-reference/v1-agent/create-agent#blueprint). ### Opus Agents An [Opus Agent](/tasks/agent/opus-agent) follows a blueprint of ordered steps instead of raw prompts. These cannot be created through the API, but one authored in the Opus app can be revised here. The blueprint itself. Fields below. What the agent is for, in one sentence. What the agent receives. The inputs, itemised. Each entry is `{ name, description }`. How the agent gets from input to output. What the agent produces. The outputs, itemised. Each entry is `{ name, description }`. Ordered steps the agent must take, each `{ name, description }`. The authoring tools expect between two and five; this endpoint does not enforce that. Longer prose about the agent, carried alongside the objective. Stored and handed back unchanged. Model the agent runs on, for example `gpt-4o`. Must be one the platform routes to. Provider of that model, for example `openai`. Must agree with the model when both are given. Model to fall back to. Validated the same way as `model`. Provider of the fallback model. Validated the same way as `provider`. `blueprint` is forwarded untouched and stored verbatim, and this endpoint does **not** check it against the agent's class — a blueprint of steps sent to a Custom Agent is stored as-is and leaves it running on empty prompts. Send the shape that matches the agent you are updating. ## Response The agent id. Agent display name. Agent description. Agent icon. Categories the agent is filed under. Agent status. Id of the new version this call created. Owning workspace, or `null` when the agent is visible across the marketplace. ## Errors Invalid body, an `agentId` that is not a UUID, or a `blueprint` naming a model or provider the platform cannot route to. Missing, invalid, or expired API key. The agent belongs to another organization, the API key is not org-scoped, or the key owner lacks the **Agent: Full** permission in the organization. No agent with that id. Rejected downstream after passing validation here. ```bash cURL theme={null} curl --request PATCH \ --url https://operator.opus.com/api/v1/agent/{AGENT_ID} \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "agent": { "name": "Adder v2", "description": "Adds two numbers and returns the total", "categories": ["numerical_computation", "aggregation_and_analysis"], "blueprint": { "systemPrompt": "You are a careful arithmetic assistant. Show no working.", "userPrompt": "Add {{firstNumber}} and {{secondNumber}} and return only the total.", "model": "gpt-4o", "provider": "openai" }, "status": "active", "isNew": false } }' ``` ```python Python theme={null} import requests agent_id = "{AGENT_ID}" url = f"https://operator.opus.com/api/v1/agent/{agent_id}" headers = { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}" } payload = { "agent": { "name": "Adder v2", "description": "Adds two numbers and returns the total", "categories": ["numerical_computation", "aggregation_and_analysis"], "blueprint": { "systemPrompt": "You are a careful arithmetic assistant. Show no working.", "userPrompt": "Add {{firstNumber}} and {{secondNumber}} and return only the total.", "model": "gpt-4o", "provider": "openai", }, "status": "active", "isNew": False, } } response = requests.patch(url, json=payload, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const agentId = "{AGENT_ID}"; const response = await fetch(`https://operator.opus.com/api/v1/agent/${agentId}`, { method: "PATCH", headers: { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}", }, body: JSON.stringify({ agent: { name: "Adder v2", description: "Adds two numbers and returns the total", categories: ["numerical_computation", "aggregation_and_analysis"], blueprint: { systemPrompt: "You are a careful arithmetic assistant. Show no working.", userPrompt: "Add {{firstNumber}} and {{secondNumber}} and return only the total.", model: "gpt-4o", provider: "openai", }, status: "active", isNew: false, }, }), }); const data = await response.json(); console.log(data); ``` ```json 200 Response theme={null} { "id": "{AGENT_ID}", "name": "Adder v2", "description": "Adds two numbers and returns the total", "icon": "{BASE64_ICON}", "categories": ["numerical_computation", "aggregation_and_analysis"], "status": "active", "versionId": "{NEW_AGENT_VERSION_ID}", "groupId": null } ``` # Case Audit Log Source: https://developer.opus.com/api-reference/v1-case/case-audit-log GET https://operator.opus.com/api/v1/case/{caseId}/audit Retrieve the per-node execution audit of a case Get a detailed, per-node view of a case's execution: which nodes ran, in what order, with which inputs and outputs, and which ones failed. Useful for progress display and debugging. ## Path Parameters The case ID returned by [Initiate Case](/api-reference/v1-case/initiate-case) ## Headers Your API authentication key ## Response Total number of nodes in the workflow The node currently running. Empty string when no node is actively running (for example, between nodes or after the case finishes). The next node to execute. Empty string when the case has no more nodes queued. Nodes not executed yet Nodes already executed Number of nodes already executed Nodes that failed Number of nodes that failed Detailed per-node execution data Per-node execution data keyed by node name or ID. Each entry has the following properties: Execution status of the node. Known values: `COMPLETED`, `FAILED`, `STARTED`, `WAITING`, `UNKNOWN` — treat as an open set; new statuses may appear. Node execution start time (epoch milliseconds) Node execution duration in milliseconds Position of the node in the execution order Input variables of the node — `{ variableName, displayName, value, type }` entries. `null` when the node has no inputs. Output variables of the node — `{ variableName, displayName, value, type }` entries. `null` when the node has no outputs. ## Errors Missing, invalid, or expired API key. The case does not exist. ```bash cURL theme={null} curl --request GET \ --url https://operator.opus.com/api/v1/case/{YOUR_CASE_ID}/audit \ --header 'x-service-key: {YOUR_SERVICE_KEY}' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/api/v1/case/{YOUR_CASE_ID}/audit" headers = {"x-service-key": "{YOUR_SERVICE_KEY}"} response = requests.get(url, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const response = await fetch( "https://operator.opus.com/api/v1/case/{YOUR_CASE_ID}/audit", { method: "GET", headers: { "x-service-key": "{YOUR_SERVICE_KEY}", }, } ); const data = await response.json(); console.log(data); ``` ```json 200 Response theme={null} { "totalNodeCount": 3, "runningNode": "", "nextNode": "", "remainingNodesToExecute": [], "executedNodes": ["Workflow Input", "Summarize", "Workflow Output"], "executedNodeCount": 3, "failedNodes": [], "failedNodeCount": 0, "audit": { "nodesExecutionData": { "Summarize": { "executionStatus": "COMPLETED", "executionStartTime": 1764755400000, "executionTime": 5230, "executionIndex": 1, "executionInput": [ { "variableName": "{VARIABLE_NAME_1}", "displayName": "Source Text", "value": "…", "type": "str" } ], "executionOutput": [ { "variableName": "{OUTPUT_VARIABLE_1}", "displayName": "Summary", "value": "…", "type": "str" } ] } } } } ``` # Introduction Source: https://developer.opus.com/api-reference/v1-case/case-introduction Run workflows and retrieve their results through the Case API ## Overview A **case** is a single run of a workflow. The Case API lets you create a case, provide its inputs, execute it, and retrieve its output — entirely through the API. Execution is asynchronous: you either poll for status or receive the result on a callback URL. ## Base URL All API requests should be made to the following base URL: ```text theme={null} https://operator.opus.com/api/v1/case/ ``` ## Authentication All Case API endpoints require authentication with your Opus API key, sent in the `x-service-key` header. ```text theme={null} x-service-key: ``` A request with a missing, invalid, or expired key returns `401`. Your API key is a unique, secret credential. Store it securely and never expose it in client-side code. ## Case Flow The typical flow for running a workflow through the API follows these steps: Fetch the workflow's input schema with [Get Workflow Details](/api-reference/v1-workflow-generation/get-workflow-details) so you know which inputs the case expects. Create a case for the workflow using `POST /case` and save the returned `caseId` — every subsequent call requires it. If the workflow has `file` or `array_files` inputs, upload each file first via the [File API](/api-reference/v1-file/file-introduction) and reference the returned `fileUrl` in your payload. Run the case using `POST /case/{caseId}/execute` with the input schema populated with values. Optionally pass a `callbackUrl` to be notified when the run finishes. Poll `GET /case/{caseId}/status` until the case reaches a terminal status — or skip polling and wait for your `callbackUrl` to be called. Use [Case Audit Log](/api-reference/v1-case/case-audit-log) for a per-node view. Once the case completes, fetch its output variables with `GET /case/{caseId}/results`. ## Usage Notes * **Asynchronous execution**: Execute Case returns immediately once the run is queued; the result arrives later via polling or your `callbackUrl`. * **Terminal statuses**: `COMPLETED`, `FAILED`, `CANCELLED`, and `TIMED_OUT` — once one is returned, the status will not change again. * **Versioning**: A case runs against the latest active version of the workflow unless you pin one with `workflowVersionId` or `workflowVersionNumber` at initiation. * **Results before completion**: Fetching results for an unfinished case returns HTTP `202` with no results — wait for a terminal status first. ## Available Endpoints Create a case for a workflow and receive a caseId Run the case with populated inputs Poll the execution status of a case Retrieve the output variables of a finished case Inspect the per-node execution audit of a case # Execute Case Source: https://developer.opus.com/api-reference/v1-case/execute-case POST https://operator.opus.com/api/v1/case/{caseId}/execute Run a case with populated inputs This is the primary step where you provide all inputs and run the workflow. Case execution is asynchronous. This endpoint returns immediately once the run is queued; the final result is delivered to your `callbackUrl` (and is also retrievable via [Get Case Results](/api-reference/v1-case/get-case-results)). The request body consists of: * The `payload` — the input schema from [Get Workflow Details](/api-reference/v1-workflow-generation/get-workflow-details) with values populated for each input * An optional `callbackUrl` that Opus will POST to when the case finishes ## Path Parameters The case ID returned by [Initiate Case](/api-reference/v1-case/initiate-case) ## Headers Your API authentication key ## Body Parameters An object where each key is a variable name from your workflow's input schema, and each value is a Variable Object (see below). HTTPS URL that Opus will POST the case result to once the run finishes. Must be reachable from the Opus platform. ### Variable Object Each entry in `payload` uses your variable name as the key (e.g., `VARIABLE_NAME_1`) and maps to an object with the following properties: The value for this input (type depends on field type) The data type: str, float, bool, date, file, array, array\_files, or object Type definition of the variable, as provided by the workflow's input schema. The variable name displayed in the Opus platform UI While `displayName` is optional, omitting it may cause display glitches on the Opus platform UI. We strongly recommend including it for each input field. ## Response Whether the case execution was successfully started The case ID Status message Error payload if the case could not be started ## Errors Missing, invalid, or expired API key. The case does not exist. ```bash cURL theme={null} curl --request POST \ --url https://operator.opus.com/api/v1/case/{YOUR_CASE_ID}/execute \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "callbackUrl": "https://your-app.example.com/opus/callback", "payload": { "{VARIABLE_NAME_1}": { "value": "API Test Project", "type": "str", "displayName": "Variable Name 1" }, "{VARIABLE_NAME_2}": { "value": 45.8, "type": "float", "displayName": "Variable Name 2" } } }' ``` ```python Python theme={null} import requests case_id = "{YOUR_CASE_ID}" url = f"https://operator.opus.com/api/v1/case/{case_id}/execute" headers = { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}" } payload = { "callbackUrl": "https://your-app.example.com/opus/callback", "payload": { "{VARIABLE_NAME_1}": { "value": "API Test Project", "type": "str", "displayName": "Variable Name 1" }, "{VARIABLE_NAME_2}": { "value": 45.8, "type": "float", "displayName": "Variable Name 2" } } } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const caseId = "{YOUR_CASE_ID}"; const response = await fetch(`https://operator.opus.com/api/v1/case/${caseId}/execute`, { method: "POST", headers: { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}", }, body: JSON.stringify({ callbackUrl: "https://your-app.example.com/opus/callback", payload: { "{VARIABLE_NAME_1}": { value: "API Test Project", type: "str", displayName: "Variable Name 1", }, "{VARIABLE_NAME_2}": { value: 45.8, type: "float", displayName: "Variable Name 2", }, }, }), }); const data = await response.json(); console.log(data); ``` ```json 201 Response theme={null} { "success": true, "caseId": "{CASE_ID}", "message": "Job execution started" } ``` # Get Case Results Source: https://developer.opus.com/api-reference/v1-case/get-case-results GET https://operator.opus.com/api/v1/case/{caseId}/results Retrieve the output variables of a finished case Fetch the output of a case once it has finished. Each entry in `results` is an output variable from the workflow's output schema with its resolved value. If you provided a `callbackUrl` in [Execute Case](/api-reference/v1-case/execute-case), the same results are also POSTed to it when the case finishes — polling this endpoint is not required in that setup. ## Path Parameters The case ID returned by [Initiate Case](/api-reference/v1-case/initiate-case) ## Headers Your API authentication key ## Response The case's output variables keyed by variable name. The resolved value of the output variable The data type of the variable (e.g. `str`, `float`, `file`) Human-readable name of the variable If the case has not finished yet, the endpoint responds with HTTP `202 Accepted` and no results. Poll [Get Case Status](/api-reference/v1-case/get-case-status) until the case reaches a terminal status before fetching results. ## Errors The case has not finished yet — results are not available. Retry later. Missing, invalid, or expired API key. The case does not exist. ```bash cURL theme={null} curl --request GET \ --url https://operator.opus.com/api/v1/case/{YOUR_CASE_ID}/results \ --header 'x-service-key: {YOUR_SERVICE_KEY}' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/api/v1/case/{YOUR_CASE_ID}/results" headers = {"x-service-key": "{YOUR_SERVICE_KEY}"} response = requests.get(url, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const response = await fetch( "https://operator.opus.com/api/v1/case/{YOUR_CASE_ID}/results", { method: "GET", headers: { "x-service-key": "{YOUR_SERVICE_KEY}", }, } ); const data = await response.json(); console.log(data); ``` ```json 200 Response theme={null} { "results": { "{OUTPUT_VARIABLE_1}": { "value": "The generated summary text", "type": "str", "displayName": "Summary" }, "{OUTPUT_VARIABLE_2}": { "value": "https://files.opus.com/...", "type": "file", "displayName": "Generated Report" } } } ``` ```json 202 Response (still running) theme={null} { "statusCode": 202, "message": "V2 job results not yet available for job with ID {CASE_ID}", "timestamp": "2026-08-05T10:15:00.000Z", "path": "/api/v1/case/{CASE_ID}/results", "errorCode": "" } ``` # Get Case Status Source: https://developer.opus.com/api-reference/v1-case/get-case-status GET https://operator.opus.com/api/v1/case/{caseId}/status Poll the execution status of a case Check the current execution status of a case. Poll this endpoint until the case reaches a terminal status, then fetch the output via [Get Case Results](/api-reference/v1-case/get-case-results). ## Path Parameters The case ID returned by [Initiate Case](/api-reference/v1-case/initiate-case) ## Headers Your API authentication key ## Response Execution status of the case. One of: `PENDING`, `IN_PROGRESS`, `WAITING`, `COMPLETED`, `FAILED`, `CANCELLED`, `TIMED_OUT`, `UNKNOWN`. Terminal statuses are `COMPLETED`, `FAILED`, `CANCELLED` and `TIMED_OUT` — once one of these is returned, the status will not change again. ## Errors Missing, invalid, or expired API key. The case does not exist. ```bash cURL theme={null} curl --request GET \ --url https://operator.opus.com/api/v1/case/{YOUR_CASE_ID}/status \ --header 'x-service-key: {YOUR_SERVICE_KEY}' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/api/v1/case/{YOUR_CASE_ID}/status" headers = {"x-service-key": "{YOUR_SERVICE_KEY}"} response = requests.get(url, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const response = await fetch( "https://operator.opus.com/api/v1/case/{YOUR_CASE_ID}/status", { method: "GET", headers: { "x-service-key": "{YOUR_SERVICE_KEY}", }, } ); const data = await response.json(); console.log(data); ``` ```json 200 Response theme={null} { "status": "IN_PROGRESS" } ``` # Initiate Case Source: https://developer.opus.com/api-reference/v1-case/initiate-case POST https://operator.opus.com/api/v1/case Create a new case for a workflow and receive a caseId This step creates a case for a workflow and returns the unique `caseId` required for execution and monitoring. A case is a single run of a workflow. Identify the workflow with the `workflowId` returned by the [workflow endpoints](/api-reference/v1-workflow-generation/get-workflow-details). The case runs against the latest active version of the workflow unless you pin one with `workflowVersionId` or `workflowVersionNumber`. You must save the `caseId` returned by this endpoint for all subsequent steps. ## Headers Your API authentication key ## Body Parameters The workflow to run — the `workflowId` UUID returned by the workflow endpoints. Pin the case to a specific workflow version by UUID. Omit to run the latest active version. Pin the case to a specific workflow version by version number. Omit to run the latest active version. Case title shown in the Opus UI Case description shown in the Opus UI ## Response The unique identifier for this case. Use this ID in all subsequent API calls. ## Errors Missing, invalid, or expired API key. The workflow does not exist. ```bash cURL theme={null} # Latest active version (minimal) curl --request POST \ --url https://operator.opus.com/api/v1/case \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "workflowId": "{YOUR_WORKFLOW_ID}", "title": "Q4 Report Processing", "description": "Processing quarterly financial reports" }' # Pinned to a specific version number curl --request POST \ --url https://operator.opus.com/api/v1/case \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "workflowId": "{YOUR_WORKFLOW_ID}", "workflowVersionNumber": 3, "title": "Q4 Report Processing" }' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/api/v1/case" headers = { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}" } payload = { "workflowId": "{YOUR_WORKFLOW_ID}", # Pin a specific workflow version (omit both to use the latest active version): # "workflowVersionNumber": 3, # "workflowVersionId": "{WORKFLOW_VERSION_ID}", "title": "Q4 Report Processing", "description": "Processing quarterly financial reports" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const response = await fetch("https://operator.opus.com/api/v1/case", { method: "POST", headers: { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}", }, body: JSON.stringify({ workflowId: "{YOUR_WORKFLOW_ID}", // Pin a specific workflow version (omit both to use the latest active version): // workflowVersionNumber: 3, // workflowVersionId: "{WORKFLOW_VERSION_ID}", title: "Q4 Report Processing", description: "Processing quarterly financial reports", }), }); const data = await response.json(); console.log(data); ``` ```json 201 Response theme={null} { "caseId": "{CASE_ID}" } ``` # Introduction Source: https://developer.opus.com/api-reference/v1-code/code-introduction Author code nodes for your organization entirely through the API ## Overview The Code API lets you register your own Python code nodes in the Opus marketplace programmatically — the source the node runs, and the typed inputs and outputs it exposes to a workflow. These endpoints author the code **catalog**: the definition of a code node, shared across your whole organization. Connecting a code node into a workspace so a workflow can run it is a separate, workspace-scoped step done in the Opus app. ## Base URL All API requests should be made to the following base URL: ``` https://operator.opus.com/api/v1/code ``` ## Authentication All API endpoints require authentication with your Opus API key, sent in the `x-service-key` header. ```text theme={null} x-service-key: ``` Your key determines your identity and your organization. Every endpoint here requires the **Code: Full** permission **at organization level** — a workspace-level grant is not sufficient, because a code node authored here belongs to the organization rather than to a workspace. A request with a missing, invalid, or expired key returns `401`. A key that is not org-scoped, or whose owner lacks **Code: Full** in the organization, returns `403`. Your API key is a unique, secret credential. Store it securely and never expose it in client-side code. Your organization must be verified to author code. Unlike some other sections, this is checked before your request is processed — an unverified organization is rejected with `403`, not further down the stack. ## Authoring Flow Authoring a code node takes a single call. Unlike the [Integrations API](/api-reference/v1-integration/integration-introduction), there is no provider to create first — your organization's code provider is resolved for you. `POST /` registers the node under your organization with its source and IO schema. Keep the returned `id`. `PATCH /{codeId}` updates any subset of fields. Each call cuts a new code version, so the previous state stays addressable. There is no `providerId` field anywhere in this section. The organization comes from your API key and the code service resolves that organization's canonical provider itself — accepting one from the caller would allow authoring into another organization's provider. If you send one, it is ignored. ## Writing the Source `sourceCode` is a Python module that must define `main`. It is called with a **single dictionary** holding every declared input, keyed by `variableName`, and must return a dictionary keyed by your declared output names: ```python theme={null} import re def main(inputs): raw_text = inputs.get("raw_text") or "" return {"clean_text": re.sub(r"\s+", " ", raw_text).strip()} ``` `main` takes one argument, not one parameter per input. A module without a `main`, or one whose `main` expects named parameters, fails at execution with `main(inputs) not defined` or a `TypeError` — neither is caught at authoring time. Your code runs in the same environment as code authored in the Opus app, with the same curated package set. See [Available Packages](/opus-sdk/available-packages) and the [Opus SDK overview](/opus-sdk/overview). `Opus` is a reserved name. The SDK object is injected into your module *after* it is imported and before `main` runs, so it is available inside `main` but not at module level — and defining your own `Opus` is rejected with `Opus is a reserved keyword`. ### Security scanning Source is scanned before it is stored. Code importing a blocked module, or using a prohibited construct, is rejected with `400` and a `violations` array naming the line, column and reason: ```json theme={null} { "statusCode": 400, "metadata": { "violations": [ { "line": 1, "col": 0, "message": "Blocked import: 'os'" } ] } } ``` The scan covers prohibited patterns, not the whole package whitelist. An import that is merely *not on the list* — rather than explicitly blocked — passes authoring and fails when the node runs. Check [Available Packages](/opus-sdk/available-packages) before you publish. ## Inputs and Outputs `inputs` and `outputs` describe the code node's signature to the workflow builder. Both are maps keyed by the variable's own `variableName`: ```json theme={null} { "raw_text": { "id": "1", "variableName": "raw_text", "displayName": "Raw Text", "allowedTypes": [{ "type": "str" }] } } ``` The key and the `variableName` inside it must match. Each variable needs at least one entry in `allowedTypes`; for composite types, `allowedTypes[].typeDefinition` describes the shape inside. The field names are camelCase, but a `variableName` **value** is the key your code reads out of the `inputs` dictionary, so it follows Python convention rather than ours. `"variableName": "raw_text"` pairs with `inputs.get("raw_text")`. ## Usage Notes * **Nothing is workspace-scoped.** A code node authored here belongs to your organization. No workspace id is accepted anywhere in this section. * **A code node is not runnable on create.** It is a catalog entry until it is connected into a workspace. * **Update replaces, it does not merge.** `sourceCode`, `inputs` and `outputs` are swapped wholesale by `PATCH`. Send the complete value you want stored. * **`sourceCode` is capped in bytes, not characters.** The limit is measured on the UTF-8 encoding, so non-ASCII source counts for more than its length — see [Limits](#limits). * **Every write cuts a version.** Both endpoints return a `versionId`, and it differs on every successful call. * **There is no read or delete.** This section authors only; it has no `GET` and no `DELETE`. Store the `id` returned by create — you cannot look it up again here. ## Limits | Field | Limit | | - | - | | `name` | 255 characters | | `description` | 2,048 characters | | `icon` | 65,535 characters | | `sourceCode` | 262,144 bytes, UTF-8 encoded | | `categories` | 5 entries | | `inputs` / `outputs` | 100 variables, 512KB JSON-encoded | | `allowedTypes` | 1–11 entries per variable | | `tags` / `options` / `nonEditableFields` | 20 entries each | ## Available Endpoints Register a Python code node with its source and IO schema Revise a code node your organization owns, cutting a new version # Create a Code Node Source: https://developer.opus.com/api-reference/v1-code/create-code POST https://operator.opus.com/api/v1/code Register a Python code node with its source and IO schema Register a Python code node in the marketplace under your organization. The node is authored at the organization level, so it is not bound to a workspace and is not runnable until it is connected into one. Returns the code `id`, which you pass to [Update a Code Node](/api-reference/v1-code/update-code). Requires the **Code: Full** permission at organization level, and a verified organization. There is no provider call to make first. Your organization's code provider is resolved for you, and `providerId` is not accepted in the body. ## Headers Your API authentication key ## Body Parameters The code node is nested under a `code` key. The code node to create. Fields below. Code node display name. Maximum 255 characters. What the code does, shown under its name. Maximum 2048 characters. Code icon as a base64-encoded SVG (or PNG) — a plain string, with no `data:` prefix. Maximum 65535 characters. The Python source the node runs. Must define `main(inputs)`. Maximum 262144 bytes when UTF-8 encoded. See [Writing the source](/api-reference/v1-code/code-introduction#writing-the-source). Categories the code node is filed under in the marketplace. Maximum 5 entries. See [Categories](#categories). The node's input schema, keyed by each variable's `variableName`. Maximum 100 entries and 512KB JSON-encoded. See [Variable object](#variable-object). The node's output schema, keyed by each variable's `variableName`. Same shape and limits as `inputs`. Code status — `active`, `inactive`, `soon` or `deprecated`. Show the "new" badge on the code tile. Show the "popular" badge on the code tile. Show the "beta" badge on the code tile. Your organization is always taken from the API key — it cannot be set in the body. Nothing here is workspace-scoped. Fields the API does not recognise, including `providerId`, are dropped rather than rejected. ## Variable object Each value inside `inputs` and `outputs`. The map key must equal the variable's `variableName`. Stable identifier for the variable, unique within the schema. Maximum 255 characters. Programmatic key. Must equal the key this entry sits under. This is the key your code reads out of the `inputs` dictionary, or returns in the result dictionary, so it follows Python naming rather than camelCase. Maximum 255 characters. Value types this variable accepts. Between 1 and 11 entries. Each has a `type` — one of `int`, `float`, `bool`, `str`, `object`, `file`, `array`, `date`, `binary`, `json_string`, `node` — plus optional `typeDefinition` and `typeDefinitionEnforced`. Human-readable label rendered in the workflow builder. Maximum 255 characters. When omitted, the code service applies its own default. Description shown next to the variable in the builder. Maximum 2048 characters. Pre-filled default value. Its type must match one of `allowedTypes`. When true, the workflow may leave this variable unset. Annotations the builder uses for grouping and filtering, each `{ variableName, value, description }`. Maximum 20. Enum-style choice list. When non-empty the builder renders a dropdown. Each entry is free-form JSON. Maximum 20. Which of `allowedTypes` is currently active. Must be one of them — consumers fall back to the first entry when unset. Fields the builder locks, preventing the workflow author from changing them — any of `variable_name`, `display_name`, `description`, `is_nullable`, `tags`, `options`, `allowed_types`. Maximum 20. When false, the builder hides the "remove variable" affordance. For composite types, `typeDefinition` describes the shape inside: a nested variable map for `object`, a single nested variable for `array`, or a date format string for `date`. Omit it for scalars. Set `typeDefinitionEnforced` to hold the workflow author to it exactly. ## Categories One to five of: `parsing_and_serialization`, `validation_and_normalization`, `transformation_and_mapping`, `aggregation_and_analysis`, `numerical_computation`, `statistical_computation`, `optimization_and_search`, `text_processing`, `document_and_ocr_processing`, `media_processing`, `control_flow_and_orchestration`, `state_and_caching`, `io_and_storage`, `networking_and_apis`, `security_and_identity`. ## Response The code id. Pass it as `{codeId}` to [Update a Code Node](/api-reference/v1-code/update-code). There is no endpoint to look this up again — store it. Code node display name. Code node description. Id of the version this call created. The response echoes only these four fields. `icon`, `categories`, `status` and the badge flags are stored but not returned. ## Errors Invalid body — a missing required field, a value over its limit, more than 5 categories, an unrecognised category or status, an `inputs`/`outputs` entry that is not a valid variable, or source that failed the security scan. A scan failure carries a `violations` array. Missing, invalid, or expired API key. Your organization is not verified to author code, the API key is not org-scoped, or the key owner lacks the **Code: Full** permission in the organization. ```bash cURL theme={null} curl --request POST \ --url https://operator.opus.com/api/v1/code \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "code": { "name": "Normalize Text", "description": "Collapses runs of whitespace in OCR output", "icon": "{BASE64_ICON}", "sourceCode": "import re\n\n\ndef main(inputs):\n raw_text = inputs.get(\"raw_text\") or \"\"\n\n return {\"clean_text\": re.sub(r\"\\s+\", \" \", raw_text).strip()}\n", "categories": ["text_processing"], "inputs": { "raw_text": { "id": "1", "variableName": "raw_text", "displayName": "Raw Text", "allowedTypes": [{ "type": "str" }] } }, "outputs": { "clean_text": { "id": "1", "variableName": "clean_text", "displayName": "Clean Text", "allowedTypes": [{ "type": "str" }] } } } }' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/api/v1/code" headers = { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}" } source = '''import re def main(inputs): raw_text = inputs.get("raw_text") or "" return {"clean_text": re.sub(r"\\s+", " ", raw_text).strip()} ''' payload = { "code": { "name": "Normalize Text", "description": "Collapses runs of whitespace in OCR output", "icon": "{BASE64_ICON}", "sourceCode": source, "categories": ["text_processing"], "inputs": { "raw_text": { "id": "1", "variableName": "raw_text", "displayName": "Raw Text", "allowedTypes": [{"type": "str"}], } }, "outputs": { "clean_text": { "id": "1", "variableName": "clean_text", "displayName": "Clean Text", "allowedTypes": [{"type": "str"}], } }, } } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const source = `import re def main(inputs): raw_text = inputs.get("raw_text") or "" return {"clean_text": re.sub(r"\\s+", " ", raw_text).strip()} `; const response = await fetch("https://operator.opus.com/api/v1/code", { method: "POST", headers: { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}", }, body: JSON.stringify({ code: { name: "Normalize Text", description: "Collapses runs of whitespace in OCR output", icon: "{BASE64_ICON}", sourceCode: source, categories: ["text_processing"], inputs: { raw_text: { id: "1", variableName: "raw_text", displayName: "Raw Text", allowedTypes: [{ type: "str" }], }, }, outputs: { clean_text: { id: "1", variableName: "clean_text", displayName: "Clean Text", allowedTypes: [{ type: "str" }], }, }, }, }), }); const data = await response.json(); console.log(data); ``` ```json 201 Response theme={null} { "id": "{CODE_ID}", "name": "Normalize Text", "description": "Collapses runs of whitespace in OCR output", "versionId": "{CODE_VERSION_ID}" } ``` # Update a Code Node Source: https://developer.opus.com/api-reference/v1-code/update-code PATCH https://operator.opus.com/api/v1/code/{codeId} Revise a code node your organization owns, cutting a new version Revise a code node your organization owns. Every field is optional — omitted fields keep their current value. Each call cuts a new code version rather than editing in place, so the previous state stays addressable. Use the `id` returned by [Create a Code Node](/api-reference/v1-code/create-code) as `{codeId}`. Requires the **Code: Full** permission at organization level, and a verified organization. `sourceCode`, `inputs` and `outputs` are replaced **wholesale**, not merged field by field. Send the complete value you want stored — a partial `inputs` map drops every variable you left out. Omitting `sourceCode` carries the current version's source forward unchanged, so you can revise metadata without resending the module. ## Headers Your API authentication key ## Path Parameters The code node to revise. This is `id` from [Create a Code Node](/api-reference/v1-code/create-code) — not its `versionId`. Must be a UUID. ## Body Parameters The code node is nested under a `code` key. The fields to change. All of them are optional. Code node display name. Maximum 255 characters. What the code does, shown under its name. Maximum 2048 characters. Code icon as a base64-encoded SVG (or PNG) — a plain string, with no `data:` prefix. Maximum 65535 characters. Replacement Python source. Must define `main(inputs)`. Replaces the stored source wholesale. Maximum 262144 bytes when UTF-8 encoded. Omit to carry the current source forward. Replacement input schema, keyed by each variable's `variableName`. Same shape and limits as on create — see [Variable object](/api-reference/v1-code/create-code#variable-object). Replacement output schema. Same shape and limits as `inputs`. Replacement category list. Maximum 5 entries. See [Categories](/api-reference/v1-code/create-code#categories). Code status — `active`, `inactive`, `soon` or `deprecated`. Show the "new" badge on the code tile. Show the "popular" badge on the code tile. Show the "beta" badge on the code tile. ## Response The code id, unchanged. Code node display name. Code node description. Id of the new version this call created. Differs on every successful call, including one that changes only a badge. The response echoes only these four fields. `icon`, `categories`, `status` and the badge flags are stored but not returned. ## Errors Invalid body, a `codeId` that is not a UUID, an `inputs`/`outputs` entry that is not a valid variable, or source that failed the security scan. A scan failure carries a `violations` array. Missing, invalid, or expired API key. The code node belongs to another organization, your organization is not verified to author code, the API key is not org-scoped, or the key owner lacks the **Code: Full** permission in the organization. No code node with that id. ```bash cURL theme={null} curl --request PATCH \ --url https://operator.opus.com/api/v1/code/{CODE_ID} \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "code": { "description": "Collapses runs of whitespace and lowercases the result", "sourceCode": "import re\n\n\ndef main(inputs):\n raw_text = inputs.get(\"raw_text\") or \"\"\n\n return {\"clean_text\": re.sub(r\"\\s+\", \" \", raw_text).strip().lower()}\n", "categories": ["text_processing", "validation_and_normalization"], "status": "active", "isNew": false } }' ``` ```python Python theme={null} import requests code_id = "{CODE_ID}" url = f"https://operator.opus.com/api/v1/code/{code_id}" headers = { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}" } source = '''import re def main(inputs): raw_text = inputs.get("raw_text") or "" return {"clean_text": re.sub(r"\\s+", " ", raw_text).strip().lower()} ''' payload = { "code": { "description": "Collapses runs of whitespace and lowercases the result", "sourceCode": source, "categories": ["text_processing", "validation_and_normalization"], "status": "active", "isNew": False, } } response = requests.patch(url, json=payload, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const codeId = "{CODE_ID}"; const source = `import re def main(inputs): raw_text = inputs.get("raw_text") or "" return {"clean_text": re.sub(r"\\s+", " ", raw_text).strip().lower()} `; const response = await fetch(`https://operator.opus.com/api/v1/code/${codeId}`, { method: "PATCH", headers: { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}", }, body: JSON.stringify({ code: { description: "Collapses runs of whitespace and lowercases the result", sourceCode: source, categories: ["text_processing", "validation_and_normalization"], status: "active", isNew: false, }, }), }); const data = await response.json(); console.log(data); ``` ```json 200 Response theme={null} { "id": "{CODE_ID}", "name": "Normalize Text", "description": "Collapses runs of whitespace and lowercases the result", "versionId": "{NEW_CODE_VERSION_ID}" } ``` # Introduction Source: https://developer.opus.com/api-reference/v1-discovery/discovery-introduction Read a discovered business process — its steps, branches, and the data flowing through them ## Overview The Business Process Discovery API gives you programmatic access to the processes mapped in Opus Discovery. A discovered process is the structured record of how work actually happens: the steps, the order and branching between them, who performs each one, the systems touched, the rules applied, and the pain points recorded along the way. Use it to pull a process into your own tooling — reporting, audits, migration into another system, or as the input to a workflow you build elsewhere. ## Base URL All API requests should be made to the following base URL: ``` https://operator.opus.com/api/v1/discovery/ ``` ## Authentication All API endpoints require authentication with your Opus API key, sent in the `x-service-key` header. ```text theme={null} x-service-key: ``` Your key determines your identity: the acting user, your organization, and the workspaces you can reach. Reading a process additionally requires the **Discovery: Read** permission in the workspace that owns it. A request with a missing, invalid, or expired key returns `401`. Keys are rate limited — sustained bursts return `429`. Your API key is a unique, secret credential. Store it securely and never expose it in client-side code. ## Current State or a Saved Version A process changes as it is refined. Every read is one of two things: * **The current state** — omit `processVersionId`. This is the live process as it stands right now. * **A saved version** — pass `processVersionId` to read the snapshot captured when that version was saved. Both return the same response shape, so code written against one works against the other. ## What a Process Contains Ordered units of work, each with an owner, duration, status, and the inputs, outputs, systems, rules, departments, performers and pain points recorded on it The connections between steps, including the branching paths Inputs, outputs, systems and rules that apply to the process as a whole rather than a single step The country and industry the process belongs to ## Available Endpoints Retrieve a discovered process with its steps, edges and tagged items # Get a Process Source: https://developer.opus.com/api-reference/v1-discovery/get-process-details GET https://operator.opus.com/api/v1/discovery/process/{processId} Retrieve a discovered process with its steps, edges and tagged items Retrieve a discovered business process — its steps, the edges between them, and the inputs, outputs, systems and rules recorded against each step and against the process as a whole. Requires the **Discovery: Read** permission in the workspace that owns the process. Pass `processVersionId` to read a saved snapshot instead of the current state. Both return the same shape. ## Headers Your API authentication key ## Path Parameters The UUID of the process to read. ## Query Parameters A saved process version to read instead of the current process. Omit for the latest state. ## Response The process id. Process name. Process description. Process status (e.g., `approved`). The organization the process belongs to. The workspace the process belongs to. Number of steps in the process. Number of branches in the process. Set when the process was started from a business process template. Parent process in the discovery hierarchy. The process steps. See [Step object](#step-object). Edges connecting the steps. Each has `id`, `sourceStepId`, `targetStepId` and an optional `label`. Process-level inputs. Each entry is `{ id, text }`. Process-level outputs. Each entry is `{ id, text }`. Systems the process touches, merged across its steps. Each entry is `{ id, text }`. Process-level business rules. Each entry is `{ id, text }`. Process context: `country` and `industry`. Creation timestamp (ISO 8601). Last update timestamp (ISO 8601). ## Step object Each entry in `steps` carries the work itself plus everything tagged against it. Step id. Step name. Step description. Position of the step in the process order. Step type. Step status. Step owner — a user id or a display name. Whether the step has been approved (locked). Scalar duration, expressed in `durationUnit`. Unit for the scalar duration. Active-duration range as `{ min, max }`, each a `{ value, unit }` bound. Null when the step only has the scalar duration. Waiting time after this step, in the same `{ min, max }` shape. Branch this step belongs to. Label of the branch. Step the branch splits from. Step the branch rejoins at. Order of this branch among its siblings. Group the step belongs to. Step inputs. Each entry is `{ id, text }`. Step outputs. Each entry is `{ id, text }`. Systems the step touches. Business rules applied at this step. Departments involved. People or roles performing the step. Pain points recorded on the step. ## Errors `processId` or `processVersionId` is not a valid UUID. Missing, invalid, or expired API key. You do not have access to this process — it belongs to another organization, or the key's user lacks the **Discovery: Read** permission in its workspace. The process does not exist, or the given version does not belong to it. ```bash cURL theme={null} curl --request GET \ --url https://operator.opus.com/api/v1/discovery/process/{PROCESS_ID} \ --header 'x-service-key: {YOUR_SERVICE_KEY}' ``` ```python Python theme={null} import requests process_id = "{PROCESS_ID}" url = f"https://operator.opus.com/api/v1/discovery/process/{process_id}" headers = {"x-service-key": "{YOUR_SERVICE_KEY}"} response = requests.get(url, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const processId = "{PROCESS_ID}"; const response = await fetch( `https://operator.opus.com/api/v1/discovery/process/${processId}`, { method: "GET", headers: { "x-service-key": "{YOUR_SERVICE_KEY}" }, } ); const data = await response.json(); console.log(data); ``` ```json 200 Response theme={null} { "id": "{PROCESS_ID}", "name": "Invoice Approval", "description": "", "status": "approved", "organizationId": "{ORGANIZATION_ID}", "workspaceId": "{WORKSPACE_ID}", "stepCount": 8, "branchCount": 2, "processOrigin": null, "parentProcessId": null, "steps": [ { "id": "{STEP_ID}", "name": "Invoice Request Received", "description": "A request or bill arrives from a supplier.", "stepOrder": 1, "stepType": "task", "status": "approved", "owner": "Accounts Payable", "locked": true, "duration": 15, "durationUnit": "minutes", "durationRange": null, "waitingTimeRange": null, "branchId": null, "branchLabel": null, "branchSourceStepId": null, "branchRejoinStepId": null, "branchOrder": 0, "groupId": null, "inputs": [{ "id": "{ITEM_ID}", "text": "Supplier invoice" }], "outputs": [{ "id": "{ITEM_ID}", "text": "Logged invoice record" }], "integrations": [{ "id": "{ITEM_ID}", "text": "Email" }], "rules": [], "departments": [{ "id": "{ITEM_ID}", "text": "Finance" }], "performers": [{ "id": "{ITEM_ID}", "text": "AP Clerk" }], "painPoints": [{ "id": "{ITEM_ID}", "text": "Invoices arrive in inconsistent formats" }] } ], "customEdges": [ { "id": "{EDGE_ID}", "sourceStepId": "{STEP_ID}", "targetStepId": "{STEP_ID}", "label": null } ], "processInputs": [], "processOutputs": [], "processIntegrations": [], "processRules": [], "milestone": { "country": "United Arab Emirates", "industry": "Financial Services" }, "createdAt": "2026-08-13T08:00:00.000Z", "updatedAt": "2026-08-13T09:12:44.000Z" } ``` # Introduction Source: https://developer.opus.com/api-reference/v1-file/file-introduction Upload files to use as case inputs through the File API ## Overview The File API lets you upload files that your workflows take as inputs (type: `file` or `array_files`). Uploading is a two-step process: request a presigned URL from Opus, then upload the file's binary content directly to that URL. ## Base URL All API requests should be made to the following base URL: ```text theme={null} https://operator.opus.com/api/v1/file/ ``` ## Authentication The [Get Upload URL](/api-reference/v1-file/get-upload-url) endpoint requires authentication with your Opus API key, sent in the `x-service-key` header. ```text theme={null} x-service-key: ``` A request with a missing, invalid, or expired key returns `401`. The [Upload File](/api-reference/v1-file/upload-file) step goes to **AWS S3**, not the Opus API — do not include the `x-service-key` header on that request. Your API key is a unique, secret credential. Store it securely and never expose it in client-side code. ## Upload Flow The typical flow for uploading a file follows these steps: Request an upload URL using `POST /upload/presigned`, providing the file extension and a target `workspaceId` or `workflowId`. Call it once for **each file** you need to upload. `PUT` the file's raw binary content to the returned `presignedUrl` with the matching `Content-Type` header. Use the `fileUrl` returned by Get Upload URL as the input value in your [Execute Case](/api-reference/v1-case/execute-case) payload. ## Usage Notes * **Size limit**: Files exceeding **10 MB** are rejected. * **One URL per file**: Each presigned URL covers a single file — request a new one for every upload. * **Workspace check**: Every upload is checked against a workspace; provide either `workspaceId` or `workflowId` when requesting the URL. * **Access scope**: Files are uploaded as **unlisted** by default — tracked by the platform but not shown in the file library. Pass `accessScope: "workspace"` to make them visible there. * **Supported types**: `.pdf`, `.docx`, `.csv`, `.xls`, `.xlsx`, `.txt`, `.json`, `.html`, `.xml`, `.jpeg`, `.jpg`, `.png` — see [Get Upload URL](/api-reference/v1-file/get-upload-url) for the full table. ## Available Endpoints Generate a presigned URL for uploading a file Upload your file's binary content to the presigned URL # Get Upload URL Source: https://developer.opus.com/api-reference/v1-file/get-upload-url POST https://operator.opus.com/api/v1/file/upload/presigned Generate a presigned URL for uploading files to use as case inputs If your workflow contains file inputs (type: `file` or `array_files`), you must upload files before executing the case. This endpoint generates a presigned URL for uploading. Call this endpoint once for **each file** you need to upload. After receiving the presigned URL, proceed to [Upload File](/api-reference/v1-file/upload-file) to complete the upload. ## Headers Your API authentication key ## Body Parameters The file extension including the dot (e.g., `.pdf`, `.docx`) Access scope for the file. Options: `workspace`, `unlisted`. If omitted, the file is uploaded as **unlisted** — tracked by the platform but not shown in the file library. The original filename of the file being uploaded (e.g., `Q4-Report.pdf`). Surfaced in the Opus file library to make the file easier to identify later. Target workspace ID (UUID) for the file — the workspace the upload is checked against. Required unless `workflowId` is provided. Target workflow ID (UUID) for the file. The workspace that owns this workflow becomes the owner of the file. Required unless `workspaceId` is provided. Every upload is checked against a workspace — you must provide either `workspaceId` or `workflowId`, regardless of `accessScope`. ## Supported File Types | Extension | Description | | - | - | | `.pdf` | PDF documents | | `.docx` | Word documents | | `.csv` | CSV spreadsheets | | `.xls`, `.xlsx` | Excel spreadsheets | | `.txt` | Plain text files | | `.json` | JSON files | | `.html` | HTML files | | `.xml` | XML files | | `.jpeg`, `.jpg`, `.png` | Image files | The maximum file size for uploads is **10 MB**. Files exceeding this limit will be rejected. ## Response Temporary URL for uploading your file. Use this in the [Upload File](/api-reference/v1-file/upload-file) step. Permanent URL to reference this file in your [Execute Case](/api-reference/v1-case/execute-case) request. ## Errors Missing, invalid, or expired API key. The workspace or workflow does not exist. ```bash cURL theme={null} curl --request POST \ --url https://operator.opus.com/api/v1/file/upload/presigned \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "fileExtension": ".pdf", "originalName": "Q4-Report.pdf", "workflowId": "{YOUR_WORKFLOW_ID}" }' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/api/v1/file/upload/presigned" headers = { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}" } payload = { "fileExtension": ".pdf", "originalName": "Q4-Report.pdf", "workflowId": "{YOUR_WORKFLOW_ID}" # Or target a workspace directly instead: # "workspaceId": "{YOUR_WORKSPACE_ID}" } response = requests.post(url, json=payload, headers=headers) data = response.json() print(data) ``` ```javascript JavaScript theme={null} const response = await fetch( "https://operator.opus.com/api/v1/file/upload/presigned", { method: "POST", headers: { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}", }, body: JSON.stringify({ fileExtension: ".pdf", originalName: "Q4-Report.pdf", workflowId: "{YOUR_WORKFLOW_ID}", // Or target a workspace directly instead: // workspaceId: "{YOUR_WORKSPACE_ID}", }), } ); const data = await response.json(); console.log(data); ``` ```json 201 Response theme={null} { "presignedUrl": "{PRESIGNED_URL}", "fileUrl": "{FILE_URL}" } ``` # Upload File Source: https://developer.opus.com/api-reference/v1-file/upload-file PUT {presignedUrl} Upload your file to the presigned URL from Get Upload URL Upload your file's binary content to the `presignedUrl` received from [Get Upload URL](/api-reference/v1-file/get-upload-url). This request goes to **AWS S3**, not the Opus API. Do not include the `x-service-key` header. ## Headers MIME type matching your file (e.g., `application/pdf`, `image/png`, `text/csv`) ## Body Raw binary data of your file. The maximum file size for uploads is **10 MB**. Requests with files exceeding this limit will be rejected. ## Response Returns HTTP `200` on success with an empty body. Reference the file afterwards via the `fileUrl` from [Get Upload URL](/api-reference/v1-file/get-upload-url) in your [Execute Case](/api-reference/v1-case/execute-case) payload. ```bash cURL theme={null} curl --request PUT \ --url "{PRESIGNED_URL}" \ --header 'Content-Type: application/pdf' \ --data-binary '@/path/to/your/file.pdf' ``` ```python Python theme={null} import requests presigned_url = "{PRESIGNED_URL}" with open("/path/to/your/file.pdf", "rb") as file: response = requests.put( presigned_url, data=file, headers={"Content-Type": "application/pdf"} ) print(response.status_code) # 200 on success ``` ```javascript JavaScript theme={null} const fs = require("fs"); const presignedUrl = "{PRESIGNED_URL}"; const fileBuffer = fs.readFileSync("/path/to/your/file.pdf"); const response = await fetch(presignedUrl, { method: "PUT", body: fileBuffer, headers: { "Content-Type": "application/pdf", }, }); console.log(response.status); // 200 on success ``` ```text 200 Response theme={null} (empty body) ``` # Connect an Integration Source: https://developer.opus.com/api-reference/v1-integration/connect-integration POST https://operator.opus.com/api/v1/integration/connect Activate an integration in a workspace with real credential values Activate an integration inside a workspace so a workflow can run it. Everything else in this section authors the **catalog** — the definition shared across your organization. This is the step that supplies the real secret values and produces the connection a workflow actually refers to. Requires the **Integration: Full** permission **in the workspace you are connecting into**, not at organization level. Your organization does not need to be verified. You can connect any integration you can see, including the ones Opus publishes — not only the ones you authored. ## Two kinds of credential How this call behaves depends on the credential the integration authenticates with. | `authType` | What happens | | - | - | | `api_key`, `basic`, `bearer`, `no_auth`, … | Connects immediately. `201` with the connection ids. | | `oauth` | Cannot complete here — a person has to authorize in a browser. `201` with an `authorizationUrl` and a `connectionToken`. | For OAuth, **nothing is connected when this call returns**. The connection only exists once someone has opened `authorizationUrl` and authorized. Use [Check a Connection](/api-reference/v1-integration/connection-status) with the `connectionToken` to find out whether they did. ## Headers Your API authentication key ## Body Parameters The connection is nested under a `connection` key. The connection to create. Fields below. Name for the connection, shown in My Integrations. Maximum 255 characters. The workspace to activate the integration in. You must hold **Integration: Full** here. The integration version to connect. This is `versionId` from [Create an Integration](/api-reference/v1-integration/create-integration). The action to enable on this connection. The credential template to authenticate with, from [Add a Credential](/api-reference/v1-integration/create-credential). Required unless you are reusing an existing connection's credential with `activeCredentialId`. The secret values, keyed by the `variableName`s of that credential template — `{ "api_key": "sk-…" }` for an API key, `{ "client_id": "…", "client_secret": "…" }` for OAuth. Encrypted before storage and never returned. Maximum 100 fields and 64KB. Reuse the credential from an existing connection instead of sending values again. Omit `credentialData` when you use this. What the connection is for. Maximum 2048 characters. An action to smoke-test the credential with once connected. The result comes back as `testPassed`. Omit it and no test runs. Inputs for that smoke test. The smoke test **really calls the action's `endpoint`** with the credential you just supplied. It is a live request to the third party, not a dry run, so pick an action that is safe to execute — a read, not a write. Whatever the endpoint answers decides the result: any 2xx or 3xx passes, anything else fails. There is no `workflowId` field. A connection belongs to a workspace, so name the workspace directly. ## Response `connected` when the connection is live, `pending_authorization` when it is waiting on OAuth. The connection — this is what a workflow refers to. `null` until an OAuth authorization completes. The connection's current version. The stored credential. Pass it as `activeCredentialId` on a later connect to reuse these secrets. The workspace the connection lives in. Whether the smoke test succeeded. `null` when you sent no `testActionVersionId`, because nothing was tested — that is not a pass. Why it failed, when it did. For a failed HTTP test this carries the status code and the first 200 characters of the response body, which for many servers is an HTML error page. Where to send a person to authorize. OAuth only. Handle for [Check a Connection](/api-reference/v1-integration/connection-status). OAuth only, and valid for **10 minutes**. ## Errors Invalid body — a missing required field, a malformed id other than `workspaceId`, neither `credentialVersionId` nor `activeCredentialId`, or `credentialData` sent together with `activeCredentialId`. Missing, invalid, or expired API key. The key owner lacks **Integration: Full** in that workspace, or the workspace belongs to another organization. A `workspaceId` that is not a UUID also lands here rather than on `400`, because the permission check runs before the body is validated. One of the ids you named does not exist: `integrationVersionId`, `actionVersionId`, `credentialVersionId`, `testActionVersionId` or `activeCredentialId`. Nothing is created when this happens. The body is well-formed but the credential is not usable as given — `credentialData` that does not match the credential template's fields, no `credentialData` for a credential that authenticates, or an OAuth credential missing `client_id` / `client_secret`. Connecting is **not idempotent**. Calling this twice with the same body creates two connections. If you retry after a timeout, check whether the first attempt succeeded. ```bash cURL theme={null} curl --request POST \ --url https://operator.opus.com/api/v1/integration/connect \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "connection": { "name": "Acme Production", "workspaceId": "{WORKSPACE_ID}", "integrationVersionId": "{INTEGRATION_VERSION_ID}", "actionVersionId": "{ACTION_VERSION_ID}", "credentialVersionId": "{CREDENTIAL_VERSION_ID}", "credentialData": { "api_key": "{ACME_API_KEY}" } } }' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/api/v1/integration/connect" headers = { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}" } payload = { "connection": { "name": "Acme Production", "workspaceId": "{WORKSPACE_ID}", "integrationVersionId": "{INTEGRATION_VERSION_ID}", "actionVersionId": "{ACTION_VERSION_ID}", "credentialVersionId": "{CREDENTIAL_VERSION_ID}", "credentialData": {"api_key": "{ACME_API_KEY}"}, } } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const response = await fetch("https://operator.opus.com/api/v1/integration/connect", { method: "POST", headers: { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}", }, body: JSON.stringify({ connection: { name: "Acme Production", workspaceId: "{WORKSPACE_ID}", integrationVersionId: "{INTEGRATION_VERSION_ID}", actionVersionId: "{ACTION_VERSION_ID}", credentialVersionId: "{CREDENTIAL_VERSION_ID}", credentialData: { api_key: "{ACME_API_KEY}" }, }, }), }); const data = await response.json(); console.log(data); ``` ```json 201 Connected theme={null} { "status": "connected", "activeIntegrationId": "{ACTIVE_INTEGRATION_ID}", "activeIntegrationVersionId": "{ACTIVE_INTEGRATION_VERSION_ID}", "activeCredentialId": "{ACTIVE_CREDENTIAL_ID}", "workspaceId": "{WORKSPACE_ID}", "testPassed": null, "testError": null } ``` ```json 201 OAuth theme={null} { "status": "pending_authorization", "activeIntegrationId": null, "authorizationUrl": "https://accounts.google.com/o/oauth2/auth?client_id=…&state=…", "connectionToken": "{CONNECTION_TOKEN}" } ``` # Check a Connection Source: https://developer.opus.com/api-reference/v1-integration/connection-status GET https://operator.opus.com/api/v1/integration/connect/{connectionToken} Read the outcome of a connection that needed authorizing Report what happened to an OAuth connection after [Connect an Integration](/api-reference/v1-integration/connect-integration) returned `pending_authorization`. An OAuth flow finishes in a browser, not in your call: a person opens the `authorizationUrl`, authorizes with the provider, and is returned to Opus. Your request is long gone by then. This endpoint is how you learn whether it worked and which connection resulted. Requires the **Integration: Read** permission in at least one workspace. The connection is matched against the workspaces you hold it in, so a token from a workspace you cannot read is reported as `expired`. Only needed for OAuth. A non-OAuth connect returns its ids immediately and there is nothing to poll. ## Headers Your API authentication key ## Path Parameters The `connectionToken` returned by [Connect an Integration](/api-reference/v1-integration/connect-integration). ## Statuses The authorization window is still open. Nobody has finished authorizing yet. Someone authorized and the connection exists. The ids are on the response. Authorization was attempted and did not complete — a denied consent screen, or a token exchange the provider rejected. The window closed without a callback, the token is not one of yours, or there is no such token at all. Start again with a fresh connect. The authorization window is **10 minutes** from the connect call. A person who takes longer — or who has to create an account with the provider first — will find the link dead, and this endpoint reports `expired`. Connect again to get a fresh `authorizationUrl`. ## Response One of `pending`, `succeeded`, `failed` or `expired`. Every field below is always present on the response; they are `null` until a connection exists. The connection — this is what a workflow refers to. Present once the status is `succeeded`. The connection's current version. The stored credential. The workspace the connection lives in. Whether the smoke test succeeded. `null` when no `testActionVersionId` was sent to connect, because nothing was tested. Why it failed, when it did. ## Errors Missing, invalid, or expired API key. The key owner lacks the **Integration: Read** permission. There is deliberately no `404`. A token that belongs to someone else, and a token that was never issued, both come back as `expired` — the same answer as one of yours that timed out. If an unknown token answered differently, this endpoint could be used to discover whether someone else's connection exists. The practical consequence: `expired` does not confirm you sent a real token. Check for a typo before assuming the window closed. ```bash cURL theme={null} curl --request GET \ --url https://operator.opus.com/api/v1/integration/connect/{CONNECTION_TOKEN} \ --header 'x-service-key: {YOUR_SERVICE_KEY}' ``` ```python Python theme={null} import time import requests token = "{CONNECTION_TOKEN}" url = f"https://operator.opus.com/api/v1/integration/connect/{token}" headers = {"x-service-key": "{YOUR_SERVICE_KEY}"} # The window is 10 minutes; give up rather than poll forever. deadline = time.time() + 600 while time.time() < deadline: status = requests.get(url, headers=headers).json() if status["status"] != "pending": break time.sleep(5) print(status) ``` ```javascript JavaScript theme={null} const token = "{CONNECTION_TOKEN}"; const url = `https://operator.opus.com/api/v1/integration/connect/${token}`; const headers = { "x-service-key": "{YOUR_SERVICE_KEY}" }; // The window is 10 minutes; give up rather than poll forever. const deadline = Date.now() + 600_000; let status; while (Date.now() < deadline) { status = await (await fetch(url, { headers })).json(); if (status.status !== "pending") break; await new Promise((resolve) => setTimeout(resolve, 5000)); } console.log(status); ``` ```json 200 Succeeded theme={null} { "status": "succeeded", "activeIntegrationId": "{ACTIVE_INTEGRATION_ID}", "activeIntegrationVersionId": "{ACTIVE_INTEGRATION_VERSION_ID}", "activeCredentialId": "{ACTIVE_CREDENTIAL_ID}", "workspaceId": "{WORKSPACE_ID}", "testPassed": null, "testError": null } ``` ```json 200 Pending theme={null} { "status": "pending", "activeIntegrationId": null, "activeIntegrationVersionId": null, "activeCredentialId": null, "workspaceId": "{WORKSPACE_ID}", "testPassed": null, "testError": null } ``` # Add a Credential Source: https://developer.opus.com/api-reference/v1-integration/create-credential POST https://operator.opus.com/api/v1/integration/v/{integrationVersionId}/credential Define how an integration authenticates Define how an integration authenticates: which fields exist, their types, and how they render in the Opus app. This is the credential **schema** — it carries no secret values. Real secrets are supplied later, when someone connects the integration inside a workspace. Use the `versionId` returned by [Create an Integration](/api-reference/v1-integration/create-integration) as `{integrationVersionId}`. Requires the **Integration: Full** permission at organization level. An integration may hold only one credential per `authType`. Adding a second with the same type returns `409`. ## Headers Your API authentication key ## Path Parameters The integration version to attach the credential to. This is `versionId` from [Create an Integration](/api-reference/v1-integration/create-integration) — not the integration's `id`. ## Body Parameters The credential is nested under a `credential` key. The credential to create. Fields below. Credential name. Maximum 255 characters. Credential icon as a base64-encoded SVG (or PNG) — a plain string, with no `data:` prefix. Maximum 65535 characters. The credential input schema, keyed by each field's `variableName`. See [Input field object](#input-field-object). Credential description. Maximum 2048 characters. Authentication type — `jwt`, `oauth`, `api_key`, `access_token`, `custom_header_auth`, `other` or `no_auth`. Credential status — `active` or `inactive`. ## Input field object Each value inside `inputs`. The map key must equal the field's `variableName`. Label rendered in the UI. Maximum 255 characters. Programmatic key for this field. Must equal the key it sits under. Maximum 255 characters. Value type accepted by this field — `str`, `int`, `float`, `bool`, `date`, `list`, `dict`, `set`, `object`, `array`, `file` or `array_files`. UI rendering order. Placeholder text shown in the input box. Maximum 255 characters. When true, the value is masked in the UI and encrypted at rest. Whether the field may be left empty. When false, the field is read-only. When false, the field is hidden from the UI but stays part of the schema. Pre-filled default value rendered in the UI. ## Response The credential id. The credential version id. Credential name. Credential description. The credential input schema, echoed back in the same shape you sent. Credential status. Credential icon. Authentication type. Creation timestamp (ISO 8601). ## Errors Invalid body — a missing required field, or a value over its limit. Missing, invalid, or expired API key. Your organization is not verified to author integrations, the key owner lacks the **Integration: Full** permission, or the integration belongs to another organization. The integration version does not exist. Check you are using `versionId` and not the integration's `id`. This integration already has a credential with the same `authType`. Rejected downstream after passing validation here. ```bash cURL theme={null} curl --request POST \ --url https://operator.opus.com/api/v1/integration/v/{INTEGRATION_VERSION_ID}/credential \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "credential": { "name": "Acme API Key", "description": "API key for the Acme Search API", "icon": "{BASE64_ICON}", "authType": "api_key", "inputs": { "api_key": { "displayName": "API Key", "variableName": "api_key", "type": "str", "order": 1, "placeholder": "Enter your Acme API key", "isSecret": true } } } }' ``` ```python Python theme={null} import requests version_id = "{INTEGRATION_VERSION_ID}" url = f"https://operator.opus.com/api/v1/integration/v/{version_id}/credential" headers = { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}" } payload = { "credential": { "name": "Acme API Key", "description": "API key for the Acme Search API", "icon": "{BASE64_ICON}", "authType": "api_key", "inputs": { "api_key": { "displayName": "API Key", "variableName": "api_key", "type": "str", "order": 1, "placeholder": "Enter your Acme API key", "isSecret": True, } }, } } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const versionId = "{INTEGRATION_VERSION_ID}"; const response = await fetch( `https://operator.opus.com/api/v1/integration/v/${versionId}/credential`, { method: "POST", headers: { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}", }, body: JSON.stringify({ credential: { name: "Acme API Key", description: "API key for the Acme Search API", icon: "{BASE64_ICON}", authType: "api_key", inputs: { api_key: { displayName: "API Key", variableName: "api_key", type: "str", order: 1, placeholder: "Enter your Acme API key", isSecret: true, }, }, }, }), } ); const data = await response.json(); console.log(data); ``` ```json 201 Response theme={null} { "id": "{CREDENTIAL_ID}", "name": "Acme API Key", "description": "API key for the Acme Search API", "inputs": { "api_key": { "displayName": "API Key", "variableName": "api_key", "type": "str", "order": 1, "isNullable": false, "placeholder": "Enter your Acme API key", "isSecret": true, "isEditable": true, "isVisible": true, "default": null } }, "status": "active", "icon": "{BASE64_ICON}", "authType": "api_key", "versionId": "{CREDENTIAL_VERSION_ID}", "createdAt": "2026-08-13T10:31:02.000Z" } ``` # Create an Integration Source: https://developer.opus.com/api-reference/v1-integration/create-integration POST https://operator.opus.com/api/v1/integration Register a custom integration, optionally with its actions and credential Register a custom integration under your organization. Optionally supply `actions[]` and a single `credential` inline, so an integration can be authored in one call. Returns `versionId`, which you pass to [Add a Credential](/api-reference/v1-integration/create-credential). Requires the **Integration: Full** permission at organization level. `integration.providerId` must belong to your organization. [Create a provider](/api-reference/v1-integration/create-provider) first if you do not have one. ## Headers Your API authentication key ## Body Parameters The integration is nested under an `integration` key. The integration to create. Fields below. Integration name. Maximum 255 characters. Integration icon as a base64-encoded SVG (or PNG) — a plain string, with no `data:` prefix. Maximum 65535 characters. Integration categories. Between 1 and 5 entries, for example `machine_learning_and_ai_services` or `collaboration_tools`. The provider this integration is authored under, from [Create a Provider](/api-reference/v1-integration/create-provider). Integration description. Maximum 2048 characters. Minimum plan an organization needs to connect this integration — `core`, `pro` or `scale`. Integration status — `active`, `inactive`, `soon` or `deprecated`. Show the "new" badge on the integration tile. Show the "popular" badge on the integration tile. Show the "beta" badge on the integration tile. Accepted on create but not currently echoed back in the response. Actions to create alongside the integration. Maximum 50. See [Action object](#action-object). A credential to create alongside the integration. Same shape as the body of [Add a Credential](/api-reference/v1-integration/create-credential). Your organization is always taken from the API key — it cannot be set in the body. Nothing here is workspace-scoped. ## Action object Action name. Maximum 255 characters. The external endpoint this action talks to. Metadata only — `code` is what actually executes. Maximum 2048 characters. The action's input schema, keyed by each field's `variableName`. See [Field object](#field-object). The action's output schema, keyed by each field's `variableName`. Action description. Maximum 2048 characters. Python source that runs when the action executes. Evaluated in the global scope, not wrapped in a function: read caller values from `input_data[...]` and the connected secret from `credential_value`, then assign to `result[...]`. Maximum 65535 characters. ## Field object Each value inside `inputs` and `outputs`. The map key must equal the field's `variableName`. Positional identifier, 1-indexed as a string — `"1"`, `"2"`, and so on. Programmatic key. Referenced from `code` as `input_data[]` for inputs, or `result[]` for outputs. Human-readable label rendered in the workflow builder. Value types this field accepts. Between 1 and 11 entries. Each has a `type` — one of `int`, `float`, `bool`, `str`, `object`, `file`, `array`, `date`, `binary`, `json_string`, `node` — plus optional `typeDefinition` and `typeDefinitionEnforced`. Description shown next to the field in the builder. Maximum 2048 characters. Pre-filled default value. Its type must match one of `allowedTypes`. When true, the workflow may omit this field at execute time. Free-form tags the builder uses for grouping and filtering. Maximum 20. Enum-style choice list. When non-empty the builder renders a dropdown. Maximum 20. Top-level field names the builder locks. Maximum 20. When false, the builder hides the "remove field" affordance. For composite types, `typeDefinition` describes the shape inside: for `array`, a single-key map naming the element; for `object`, a map of its properties. Each value is itself a field definition and may nest further, so a list of records is `array` → `object` → properties. Maximum 50 entries per map. ## Response The integration id. The integration version id. Use it as `{integrationVersionId}` in [Add a Credential](/api-reference/v1-integration/create-credential). Integration name. Integration description. Integration icon. Integration categories. Minimum plan needed to connect it. Integration status. The provider the integration was authored under. Whether the "new" badge is shown. Whether the "popular" badge is shown. Actions created inline, each `{ actionId, actionVersionId, name }`. The credential created inline, as `{ credentialId, credentialVersionId, name }`. `null` when none was supplied. ## Errors Invalid body — a missing required field, a value over its limit, more than 5 categories, or more than 50 actions. Missing, invalid, or expired API key. Your organization is not verified to author integrations, or the key owner lacks the **Integration: Full** permission in the organization. Rejected downstream after passing validation here. An inline action that fails does **not** roll back the integration — the integration row may already exist. Check before retrying, or you will create duplicates. ```bash cURL theme={null} curl --request POST \ --url https://operator.opus.com/api/v1/integration \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "integration": { "name": "Acme Search", "description": "Search the web using the Acme API", "icon": "{BASE64_ICON}", "category": ["machine_learning_and_ai_services"], "providerId": "{PROVIDER_ID}", "actions": [ { "name": "Search", "description": "Run a search query", "endpoint": "https://api.acme.com/v1/search", "code": "result[\"items\"] = search(input_data[\"query\"], credential_value)", "inputs": { "query": { "id": "1", "variableName": "query", "displayName": "Query", "allowedTypes": [{ "type": "str" }] } }, "outputs": { "items": { "id": "1", "variableName": "items", "displayName": "Items", "allowedTypes": [{ "type": "array" }] } } } ] } }' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/api/v1/integration" headers = { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}" } payload = { "integration": { "name": "Acme Search", "description": "Search the web using the Acme API", "icon": "{BASE64_ICON}", "category": ["machine_learning_and_ai_services"], "providerId": "{PROVIDER_ID}", "actions": [ { "name": "Search", "endpoint": "https://api.acme.com/v1/search", "code": 'result["items"] = search(input_data["query"], credential_value)', "inputs": { "query": { "id": "1", "variableName": "query", "displayName": "Query", "allowedTypes": [{"type": "str"}], } }, "outputs": { "items": { "id": "1", "variableName": "items", "displayName": "Items", "allowedTypes": [{"type": "array"}], } }, } ], } } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const response = await fetch("https://operator.opus.com/api/v1/integration", { method: "POST", headers: { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}", }, body: JSON.stringify({ integration: { name: "Acme Search", description: "Search the web using the Acme API", icon: "{BASE64_ICON}", category: ["machine_learning_and_ai_services"], providerId: "{PROVIDER_ID}", actions: [ { name: "Search", endpoint: "https://api.acme.com/v1/search", code: 'result["items"] = search(input_data["query"], credential_value)', inputs: { query: { id: "1", variableName: "query", displayName: "Query", allowedTypes: [{ type: "str" }], }, }, outputs: { items: { id: "1", variableName: "items", displayName: "Items", allowedTypes: [{ type: "array" }], }, }, }, ], }, }), }); const data = await response.json(); console.log(data); ``` ```json 201 Response theme={null} { "id": "{INTEGRATION_ID}", "name": "Acme Search", "description": "Search the web using the Acme API", "icon": "{BASE64_ICON}", "category": ["machine_learning_and_ai_services"], "requiredPlan": "core", "status": "active", "providerId": "{PROVIDER_ID}", "isNew": true, "isPopular": false, "versionId": "{INTEGRATION_VERSION_ID}", "createdActions": [ { "actionId": "{ACTION_ID}", "actionVersionId": "{ACTION_VERSION_ID}", "name": "Search" } ], "createdCredential": null } ``` # Create a Provider Source: https://developer.opus.com/api-reference/v1-integration/create-provider POST https://operator.opus.com/api/v1/integration/provider Register the vendor or system an integration is authored under Create the provider an integration is authored under — the vendor or system it talks to, such as Google, Slack, or an internal service of your own. The provider carries your organization, and that binding is what authorizes later action, credential and publish calls on integrations built on it. Create one before your first integration and reuse its `id` for everything from the same vendor. Requires the **Integration: Full** permission at organization level. ## Headers Your API authentication key ## Body Parameters Provider display name. Maximum 255 characters. Provider icon as a base64-encoded SVG (or PNG) — a plain string, with no `data:` prefix. Typically 360–8000 characters, maximum 65535. Provider contact email. Maximum 254 characters. Defaults automatically when omitted. Your organization is always taken from the API key — it cannot be set in the body. `email` must use a real domain. Reserved domains — `.test`, `.example`, `.invalid`, `.localhost` — are rejected with `422`. Omit the field if you do not have a real address. ## Response The provider id. Pass it as `providerId` when [creating an integration](/api-reference/v1-integration/create-integration). Provider display name. Provider contact email. Provider status — `active` or `inactive`. Provider icon. Creation timestamp (ISO 8601). Only `id` is guaranteed. The other fields may be absent, because the provider version is not loaded on create. ## Errors Invalid body — for example a `name` longer than 255 characters, or a malformed `email`. Missing, invalid, or expired API key. Your organization is not verified to author integrations, the API key is not org-scoped, or the key owner lacks the **Integration: Full** permission. Rejected downstream after passing validation here — most commonly an `email` on a reserved domain. ```bash cURL theme={null} curl --request POST \ --url https://operator.opus.com/api/v1/integration/provider \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "name": "Acme Corp" }' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/api/v1/integration/provider" headers = { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}" } payload = {"name": "Acme Corp"} response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const response = await fetch( "https://operator.opus.com/api/v1/integration/provider", { method: "POST", headers: { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}", }, body: JSON.stringify({ name: "Acme Corp" }), } ); const data = await response.json(); console.log(data); ``` ```json 201 Response theme={null} { "id": "{PROVIDER_ID}", "name": "Acme Corp", "email": "org-provider@opus.ai", "status": "active", "icon": "", "createdAt": "2026-08-13T10:24:11.000Z" } ``` # Introduction Source: https://developer.opus.com/api-reference/v1-integration/integration-introduction Author custom integrations for your organization entirely through the API ## Overview The Integrations API lets you register your own integrations in Opus programmatically — the provider they belong to, the integration itself with the actions it can perform, and the credential schema it authenticates with — and then connect one so a workflow can run it. Most of these endpoints author the integration **catalog**: the definition of an integration and the shape of its credentials, shared across your whole organization. [Connect an Integration](/api-reference/v1-integration/connect-integration) is the exception — a connection supplies the real secret values and belongs to a single workspace. ## Base URL All API requests should be made to the following base URL: ``` https://operator.opus.com/api/v1/integration/ ``` ## Authentication All API endpoints require authentication with your Opus API key, sent in the `x-service-key` header. ```text theme={null} x-service-key: ``` Your key determines your identity and your organization. The three authoring endpoints require the **Integration: Full** permission **at organization level** — a workspace-level grant is not sufficient, because what they create belongs to the organization rather than to a workspace. [Connect an Integration](/api-reference/v1-integration/connect-integration) is the other way round: it needs **Integration: Full** in the workspace you are connecting into, because that is where the connection lives. A request with a missing, invalid, or expired key returns `401`. Keys are rate limited — sustained bursts return `429`. Your API key is a unique, secret credential. Store it securely and never expose it in client-side code. Your organization must be **verified** to author integrations. An unverified organization receives `403` from the three authoring endpoints. Contact Opus support if you need your organization verified. Connecting does not require verification — you can connect any integration you can see, including the ones Opus publishes. ## Authoring Flow Creating a working integration takes three calls, in order. Each returns an id the next one needs. A fourth connects it so a workflow can use it. A provider is the vendor or system the integration talks to — Google, Slack, your own internal service. Create one with `POST /provider` and keep the returned `id`. Reuse it for every integration from the same vendor. `POST /` registers the integration under that provider, optionally with its actions inline. Keep the returned `versionId`. `POST /v/{integrationVersionId}/credential` defines how the integration authenticates — which fields exist and how they render. This is the credential **schema**, never the secret values. `POST /connect` activates the integration in a workspace with the real secret values, and returns the connection a workflow refers to. Steps 2 and 3 can be collapsed into one call: pass a `credential` object inside the integration body and it is created alongside it. ## Actions and Fields An action is one thing an integration can do. It carries an `inputs` and an `outputs` map describing its data, plus the Python `code` that runs when the action executes. Both maps are keyed by the field's own `variableName`: ```json theme={null} { "query": { "id": "1", "variableName": "query", "displayName": "Query", "allowedTypes": [{ "type": "str" }] } } ``` The key and the `variableName` inside it must match. Your `code` reads inputs from `input_data[...]` and writes outputs to `result[...]` using those same names. For composite types, `allowedTypes[].typeDefinition` describes the shape inside — for `array` a single-key map naming the element, for `object` a map of its properties. Values nest, so a list of records is `array` → `object` → properties. ## Usage Notes * **Authoring is org-wide, connecting is not.** Providers, integrations and credentials belong to your organization and accept no workspace id. A connection belongs to the one workspace you name. * **One credential per auth type.** Adding a second credential with the same `authType` to the same integration returns `409`. * **A failed action does not roll back the integration.** If an inline action is rejected, the integration itself may still have been created. Check before retrying, or you will end up with duplicates. * **`400` is us, `422` is downstream.** A `400` means this API rejected your body. A `422` means it passed validation here and was rejected further down — most often an `email` on a reserved domain. ## Available Endpoints Register the vendor or system an integration is authored under Register a custom integration, optionally with its actions and credential Define how an integration authenticates Activate an integration in a workspace with real credential values Read the outcome of a connection that needed authorizing # Agent Node Source: https://developer.opus.com/api-reference/v1-workflow-generation/agent-node The three agent handler classes and the process object each one takes An agent node (`"type": "agent"`) runs an LLM-backed step. It is the only node type with more than one handler class, and `handler_class` decides the shape of `process`. Use this page when building `nodes` for [Create a Workflow](/api-reference/v1-workflow-generation/create-workflow) or [Update a Workflow](/api-reference/v1-workflow-generation/update-workflow). ## Choosing A Class | | `agent_basic` | `agent_custom` | `agent_advanced` | | - | - | - | - | | **You supply** | A blueprint | Your own prompts | A blueprint + tools | | **Opus writes the prompts** | Yes | No | Yes | | **Can call tools** | No | No | Yes | | **Use it when** | You want the outcome specified and the prompting handled for you | You need exact control over wording | The step needs several tools or sub-agents to finish | An `agent_advanced` node **cannot be used as a tool** by another advanced agent. Only Basic and Custom agents, code utilities and integrations can be referenced in `tool_references`. ## agent\_basic You describe what the step should achieve; Opus generates the prompting. See [Blueprint](#blueprint) below. Model identifier. Defaults to an empty string, which lets Opus pick. Model provider. Defaults to an empty string. Model to fall back to if the primary is unavailable. Provider for `backup_model`. ```json agent_basic theme={null} { "id": "{NODE_ID}", "name": "Summarize Report", "type": "agent", "handler_class": "agent_basic", "process": { "blueprint": { "objective": "Summarize a quarterly financial report into five bullet points", "input_description": "A quarterly financial report as plain text", "process_description": "Read the report, identify the material changes, and condense them", "output_description": "Five bullet points, each one sentence", "input_items": [{ "name": "report_text", "description": "The full report" }], "output_items": [{ "name": "summary", "description": "Five bullets" }], "required_steps": [{ "name": "Extract figures", "description": "Pull the headline numbers" }] }, "model": "", "provider": "" } } ``` ## agent\_custom You write the prompts verbatim. Opus sends them as given. The system prompt, sent unchanged. The user prompt, sent unchanged. Model identifier. Defaults to an empty string. Model provider. Defaults to an empty string. Model to fall back to if the primary is unavailable. Provider for `backup_model`. ```json agent_custom theme={null} { "id": "{NODE_ID}", "name": "Classify Ticket", "type": "agent", "handler_class": "agent_custom", "process": { "system_prompt": "You are a support triage assistant. Reply with one word.", "user_prompt": "Classify this ticket as billing, technical or other:\n\n{{ticket_body}}", "model": "", "provider": "" } } ``` ## agent\_advanced A blueprint agent that can call other handlers as tools. See [Blueprint](#blueprint) below. Identical to the `agent_basic` blueprint. The tools this agent may call. Defaults to empty. The handlers behind those tools, keyed by tool name. ID of the handler to call Version ID of that handler Active handler ID Active handler version ID The referenced handler's node type — `agent`, `code` or `integration` The referenced handler's class. Must not be `agent_advanced`. Tool name shown to the model What the tool does — the model uses this to decide when to call it How many tool-calling rounds the agent may take before it must answer. Model identifier. Defaults to an empty string. Model provider. Defaults to an empty string. Model to fall back to if the primary is unavailable. Provider for `backup_model`. ```json agent_advanced theme={null} { "id": "{NODE_ID}", "name": "Research Vendor", "type": "agent", "handler_class": "agent_advanced", "process": { "blueprint": { "objective": "Produce a vendor risk summary", "input_description": "A vendor name", "process_description": "Look the vendor up, then summarize the findings", "output_description": "A one-paragraph risk summary" }, "tool_references": { "lookup_vendor": { "handler_id": "{HANDLER_ID}", "handler_version_id": "{HANDLER_VERSION_ID}", "handler_active_id": "{HANDLER_ACTIVE_ID}", "handler_active_version_id": "{HANDLER_ACTIVE_VERSION_ID}", "handler_type": "integration", "handler_class": "integration", "name": "lookup_vendor", "description": "Fetch a vendor record by name" } }, "max_iterations": 5 } } ``` ## Blueprint Used by `agent_basic` and `agent_advanced`. Four fields are required — the blueprint is what Opus turns into prompts, so an empty description produces a weaker agent. What this step is meant to achieve What the step takes in, described as a whole How the step should go about the work What the step hands on, described as a whole Named inputs, each `{ name, description }`. Defaults to empty. Named outputs, each `{ name, description }`. Defaults to empty. Steps the agent must carry out, each `{ name, description }`. Defaults to empty. `input_description` and `output_description` describe the step's input and output **as a whole**. Per-variable descriptions belong in [`input_schema` and `output_schema`](/api-reference/v1-workflow-generation/variable-schemas) instead. # Archive a Workflow Source: https://developer.opus.com/api-reference/v1-workflow-generation/archive-workflow DELETE https://operator.opus.com/api/v1/workflow/{workflowId} Archive a workflow, removing it from listings Archive a workflow. Archiving removes it from listings; it does not delete the workflow or its version history, and [Restore a Workflow](/api-reference/v1-workflow-generation/restore-workflow) brings it back. Requires the **Workflow: Full** permission on the workflow. A workflow that still has an **active version cannot be archived** — the call returns `400` with `WF_HAS_ACTIVE_VERSIONS`. Deactivate the workflow first by setting `activeStatus` to `inactive` via [Update a Workflow](/api-reference/v1-workflow-generation/update-workflow), then archive it. ## Path Parameters The ID of the workflow to archive ## Headers Your API authentication key ## Response The workflow ID that was archived — the same ID you supplied in the path Archive status after the call. Always `true` on a 2xx response. When the workflow was archived, ISO 8601. `null` if unknown. Display name of the user who archived the workflow. `null` if unknown. Archiving is idempotent. Archiving a workflow that is already archived succeeds and changes nothing — and `archivedAt` returns the **original** archive time, not the time of the repeat call. ## Errors The workflow still has an active version (`WF_HAS_ACTIVE_VERSIONS`) — deactivate it before archiving. Missing, invalid, or expired API key. No access to this workflow. The workflow does not exist. ```bash cURL theme={null} curl --request DELETE \ --url https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID} \ --header 'x-service-key: {YOUR_SERVICE_KEY}' ``` ```python Python theme={null} import requests response = requests.delete( "https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID}", headers={"x-service-key": "{YOUR_SERVICE_KEY}"}, ) print(response.json()) ``` ```javascript JavaScript theme={null} const response = await fetch( "https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID}", { method: "DELETE", headers: { "x-service-key": "{YOUR_SERVICE_KEY}" }, } ); const data = await response.json(); console.log(data); ``` ```json 200 Response theme={null} { "workflowId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "isArchived": true, "archivedAt": "2026-01-15T10:30:00.000Z", "archivedBy": "Ada Lovelace" } ``` ```json 400 Active Version theme={null} { "statusCode": 400, "message": "WF_HAS_ACTIVE_VERSIONS" } ``` # Cancel a Run Source: https://developer.opus.com/api-reference/v1-workflow-generation/cancel-run POST https://operator.opus.com/api/v1/workflow/{workflowId}/run/cancel Stop an in-progress generation run Stop an in-progress generation run. This stops the AI agents from doing any further work on the run. Requires the **Workflow: Full** permission in the workflow's workspace. Work already applied to the workflow is kept. Cancelling stops future work — it doesn't roll anything back. ## Path Parameters The ID of the workflow whose run you want to cancel. This is the `workflowId` returned from [Generate a Workflow](/api-reference/v1-workflow-generation/generate-headless). ## Headers Your API authentication key ## Body Parameters The specific run to cancel. Defaults to the workflow's active run. ## Response Whether the run was successfully cancelled. The ID of the cancelled run. The workflow ID. ## Errors `workflowId` is not a valid UUID, or `runId` is present but malformed. Missing, invalid, or expired API key, or the key's user is no longer a member of the organization. The user does not have access to this workflow, or lacks the **Workflow: Full** permission in its workspace. No active room or run for this workflow. ```bash cURL theme={null} curl --request POST \ --url https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID}/run/cancel \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "runId": "{YOUR_RUN_ID}" }' ``` ```python Python theme={null} import requests workflow_id = "{YOUR_WORKFLOW_ID}" url = f"https://operator.opus.com/api/v1/workflow/{workflow_id}/run/cancel" headers = { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}" } payload = {"runId": "{YOUR_RUN_ID}"} # optional — defaults to the active run response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const workflowId = "{YOUR_WORKFLOW_ID}"; const response = await fetch( `https://operator.opus.com/api/v1/workflow/${workflowId}/run/cancel`, { method: "POST", headers: { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}", }, body: JSON.stringify({ runId: "{YOUR_RUN_ID}", }), } ); const data = await response.json(); console.log(data); ``` ```json 200 Response theme={null} { "cancelled": true, "run_id": "{RUN_ID}", "workflow_id": "{WORKFLOW_ID}" } ``` # Code Node Source: https://developer.opus.com/api-reference/v1-workflow-generation/code-node Run Python as a workflow step — the code handler class and its process object A code node (`"type": "code"`) runs Python as a deterministic step. It has a single handler class, `code`, so `handler_class` and `process` are never ambiguous. Use this page when building `nodes` for [Create a Workflow](/api-reference/v1-workflow-generation/create-workflow) or [Update a Workflow](/api-reference/v1-workflow-generation/update-workflow). Reach for a code node when the work is exact and repeatable — parsing, arithmetic, reshaping data, calling a library. Where the work needs judgement, use an [Agent Node](/api-reference/v1-workflow-generation/agent-node) instead. ## Process Fields The Python source to run. Your code reads the node's inputs and returns its outputs; the variable names come from the node's `input_schema` and `output_schema`. See [Variable Schemas](/api-reference/v1-workflow-generation/variable-schemas). What the code does. Keep it accurate — this is the field most likely to go stale once the code is edited, and it is what teammates read first. What the step is meant to achieve, as distinct from how `code` achieves it. Defaults to an empty string. Python packages the code imports. Defaults to empty. Only packages available in the Opus Code runtime can be imported — see [Available Packages](/opus-sdk/available-packages). For reading and writing files from inside a code node, and the file formats Opus supports, see the [Opus SDK](/opus-sdk/overview). ## Example ```json code node theme={null} { "id": "{NODE_ID}", "name": "Normalize Invoice Totals", "type": "code", "handler_class": "code", "process": { "code": "def run(invoice_lines):\n total = sum(line['amount'] for line in invoice_lines)\n return {'total': round(total, 2)}\n", "description": "Sums invoice line amounts and rounds the total to two decimal places", "objective": "Produce a single reconciled invoice total", "libraries_used": [] } } ``` # Create a Workflow Source: https://developer.opus.com/api-reference/v1-workflow-generation/create-workflow POST https://operator.opus.com/api/v1/workflow Create a workflow in a workspace, optionally pre-populated with nodes and edges Create a workflow in the workspace named by the `x-workspace-id` header. `nodes` and `edges` are optional — omit them and Opus creates the workflow with an input node and an output node already wired, ready to open in the [Builder](/guides/builder). Supply them to stand up a complete graph in a single call. Requires the **Workflow: Full** permission in the target workspace. Prefer to describe the workflow in plain language instead of building the graph yourself? Use [Generate Workflow](/api-reference/v1-workflow-generation/generate-headless) and let Opus AI agents design it for you. ## Headers Your API authentication key UUID of the workspace to create the workflow in ## Body Parameters Workflow name Workflow description Workflow nodes keyed by node ID. Each map **key must equal the `id` of the node it holds**. A node's `handler_class` determines the shape of its `process` — see [Node Process Types](/api-reference/v1-workflow-generation/node-process-types). Node ID (UUID). Must match the key this node is stored under. Node name Node type — for example `input`, `output`, `agent`, `integration`, `code` Node description Handler ID Handler version ID Active handler ID Active handler version ID Which variety of this node type — it determines the shape of `process`. See [Node Process Types](/api-reference/v1-workflow-generation/node-process-types). Node properties. Set `route` when the node defines [routes](#routing). Input variable schema — see [Variable Schemas](/api-reference/v1-workflow-generation/variable-schemas) Output variable schema — see [Variable Schemas](/api-reference/v1-workflow-generation/variable-schemas) Variable mappings — which upstream variable feeds each input. See [Connecting Variables Between Nodes](/api-reference/v1-workflow-generation/variable-schemas#connecting-variables-between-nodes). The step's configuration. Its shape is determined by `handler_class` — see [Node Process Types](/api-reference/v1-workflow-generation/node-process-types). Conditional branches out of this node, keyed by route ID. Each map **key must equal the `id` of the route it holds**. Route ID. Must match the key this route is stored under. Route name What this route is for Fixed input/output values — see [Fixed Values](/api-reference/v1-workflow-generation/variable-schemas#fixed-values) Where the node sits on the Builder canvas. Both values are integers. Horizontal position Vertical position Omit it and the node is still valid — position is presentational only and never affects execution. Public execution settings Workflow edges keyed by edge ID. Each map **key must equal the `id` of the edge it holds**, and `from_node_id` and `to_node_id` must name nodes present in `nodes`. Edge ID (UUID). Must match the key this edge is stored under. Source node ID (UUID) Target node ID (UUID) Edge label. One of `soft` or `hard`. ID of the route this edge belongs to Whether this edge is the complement of its route Workflow active status. One of `active` or `inactive`. Org units to tag the new workflow to at creation. Maximum 100. Tagging is best-effort: if a tag can't be applied, the workflow is still created and the call still succeeds. Node and edge objects use **snake\_case** keys (`from_node_id`, `input_schema`), while the top-level body fields use **camelCase** (`activeStatus`, `orgUnitIds`). This is deliberate — nodes and edges are forwarded to the workflow executor verbatim. ## Routing A route is a conditional branch out of a node. Wiring one up touches four places, and all four must agree or the route is orphaned: Add an entry to the node's `routes`, keyed by the route ID. Add a `bool` variable to the node's `output_schema` whose **schema key is the route ID**. This variable is what the node sets at runtime to decide whether the branch is taken. Include `route` in the node's `properties`. Set `route_id` on each edge that belongs to the route. Use `route_complement` on the edge that should be taken when the route's boolean is false. ```json routing theme={null} { "routes": { "{ROUTE_ID}": { "id": "{ROUTE_ID}", "name": "Needs Approval", "description": "Taken when the amount exceeds the auto-approval limit" } }, "properties": ["route"], "output_schema": { "schema": { "{ROUTE_ID}": { "id": "{ROUTE_ID}", "variable_name": "needs_approval", "allowed_types": [{ "type": "bool" }] } }, "variable_addition_allowed": true } } ``` The matching edges then carry the route: ```json edges theme={null} "edges": { "{EDGE_A}": { "id": "{EDGE_A}", "from_node_id": "{NODE_ID}", "to_node_id": "{APPROVAL_NODE_ID}", "route_id": "{ROUTE_ID}" }, "{EDGE_B}": { "id": "{EDGE_B}", "from_node_id": "{NODE_ID}", "to_node_id": "{SKIP_NODE_ID}", "route_id": "{ROUTE_ID}", "route_complement": true } } ``` ## Response The workflow ID. Use this as `{workflowId}` in [Get Workflow Details](/api-reference/v1-workflow-generation/get-workflow-details), [Update a Workflow](/api-reference/v1-workflow-generation/update-workflow), and [Get Run Status](/api-reference/v1-workflow-generation/get-run-status). The ID of the workflow's entry in the Opus catalog. Most integrations only need `workflowId`. The ID of the first workflow version Builder type. One of `OPUS_V1` or `OPUS_V2`. ## Errors Missing or malformed `x-workspace-id` header. Missing, invalid, or expired API key. No access to that workspace. The workspace or user does not exist. ```bash cURL theme={null} # Minimal — Opus adds the input and output nodes for you curl --request POST \ --url https://operator.opus.com/api/v1/workflow \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --header 'x-workspace-id: {YOUR_WORKSPACE_ID}' \ --header 'Content-Type: application/json' \ --data '{ "name": "Quarterly Report Processor", "description": "Summarizes quarterly financial reports" }' ``` ```python Python theme={null} import requests response = requests.post( "https://operator.opus.com/api/v1/workflow", headers={ "x-service-key": "{YOUR_SERVICE_KEY}", "x-workspace-id": "{YOUR_WORKSPACE_ID}", }, json={ "name": "Quarterly Report Processor", "description": "Summarizes quarterly financial reports", "activeStatus": "inactive", }, ) print(response.json()) ``` ```javascript JavaScript theme={null} const response = await fetch("https://operator.opus.com/api/v1/workflow", { method: "POST", headers: { "x-service-key": "{YOUR_SERVICE_KEY}", "x-workspace-id": "{YOUR_WORKSPACE_ID}", "Content-Type": "application/json", }, body: JSON.stringify({ name: "Quarterly Report Processor", description: "Summarizes quarterly financial reports", }), }); const data = await response.json(); console.log(data); ``` ```json With nodes and edges theme={null} { "name": "Quarterly Report Processor", "description": "Summarizes quarterly financial reports", "activeStatus": "inactive", "nodes": { "{INPUT_NODE_ID}": { "id": "{INPUT_NODE_ID}", "name": "Workflow Input", "type": "input" }, "{OUTPUT_NODE_ID}": { "id": "{OUTPUT_NODE_ID}", "name": "Workflow Output", "type": "output" } }, "edges": { "{EDGE_ID}": { "id": "{EDGE_ID}", "from_node_id": "{INPUT_NODE_ID}", "to_node_id": "{OUTPUT_NODE_ID}" } } } ``` ```json 201 Response theme={null} { "entityId": "{ENTITY_ID}", "workflowId": "{WORKFLOW_ID}", "workflowVersionId": "{WORKFLOW_VERSION_ID}", "builderType": "OPUS_V2" } ``` # Generate a Workflow Source: https://developer.opus.com/api-reference/v1-workflow-generation/generate-headless POST https://operator.opus.com/api/v1/workflow/generate Create a workflow from a natural-language prompt Create a workflow from a plain-language prompt entirely through the API — no browser session required. Opus AI agents design and build the workflow for you, and this endpoint returns immediately with a `runId` you poll until the generation finishes. Generation is asynchronous. This endpoint creates the workflow and starts the run, then returns right away. Track progress with [Get Run Status](/api-reference/v1-workflow-generation/get-run-status) until the run reaches a terminal status. Requires the **Workflow: Full** permission in the target workspace. ## Headers Your API authentication key ## Body Parameters What to build, in plain language. Be specific: the goal, the steps you already know, decisions to be made, and the systems involved. The UUID of the workspace to create the workflow in. You must be a member of this workspace. Workflow name. Defaults to the first 60 characters of the prompt. Short title for the run. Generated automatically when omitted. Uploaded file references to give the AI as context (process docs, examples, specs). Maximum of 10. Org unit UUIDs to tag the new workflow to. Maximum of 100. Omitted or empty means no tagging. Your organization is always taken from the API key — it cannot be set in the body. ## Response The ID of the workflow's entry in the Opus catalog. Most integrations only need `workflowId`. The workflow ID. Use this as `{workflowId}` in [Get Run Status](/api-reference/v1-workflow-generation/get-run-status) and [Cancel a Run](/api-reference/v1-workflow-generation/cancel-run). The ID of the workflow version created for this generation. The generation run ID. Poll it with [Get Run Status](/api-reference/v1-workflow-generation/get-run-status). The initial run status (e.g., `processing`). Whether the run is registered and underway. `false` means the run hasn't been confirmed as started yet — check [Get Run Status](/api-reference/v1-workflow-generation/get-run-status) before relying on it. ## Errors Invalid body (bad UUIDs, more than 10 files or 100 org units), or the API key has no active organization. Missing, invalid, or expired API key, or the key's user is no longer a member of the organization. The key's user lacks the **Workflow: Full** permission in the target workspace. `No workspace found` — the workspace doesn't exist or you don't have access to it. This workflow already has a run in progress. Only one run is allowed at a time. Too many active runs. Limits are 20 per workspace and 100 per organization. The response body carries `{scope, limit, active}`. Your API key's own rate limit can also return `429`. Generation is temporarily unavailable — retry shortly. ```bash cURL theme={null} curl --request POST \ --url https://operator.opus.com/api/v1/workflow/generate \ --header 'Content-Type: application/json' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --data '{ "prompt": "Classify an incoming support email as billing or technical, then draft a reply for the chosen category.", "workspaceId": "{YOUR_WORKSPACE_ID}" }' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/api/v1/workflow/generate" headers = { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}" } payload = { "prompt": "Classify an incoming support email as billing or technical, then draft a reply for the chosen category.", "workspaceId": "{YOUR_WORKSPACE_ID}" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript JavaScript theme={null} const response = await fetch( "https://operator.opus.com/api/v1/workflow/generate", { method: "POST", headers: { "Content-Type": "application/json", "x-service-key": "{YOUR_SERVICE_KEY}", }, body: JSON.stringify({ prompt: "Classify an incoming support email as billing or technical, then draft a reply for the chosen category.", workspaceId: "{YOUR_WORKSPACE_ID}", }), } ); const data = await response.json(); console.log(data); ``` ```json 201 Response theme={null} { "entityId": "{ENTITY_ID}", "workflowId": "{WORKFLOW_ID}", "workflowVersionId": "{WORKFLOW_VERSION_ID}", "runId": "{RUN_ID}", "status": "processing", "confirmed": true } ``` # Get Run Status Source: https://developer.opus.com/api-reference/v1-workflow-generation/get-run-status GET https://operator.opus.com/api/v1/workflow/{workflowId}/run Poll the status and progress of a generation run Retrieve the current status and progress of a generation run. Use it to poll a run started by [Generate a Workflow](/api-reference/v1-workflow-generation/generate-headless) until it reaches a terminal status. Works both during and after the run. Requires the **Workflow: Read** permission in the workflow's workspace. Progress updates continuously. Polling every 3–10 seconds is plenty. ## Path Parameters The ID of the workflow whose run you want to inspect. This is the `workflowId` returned from [Generate a Workflow](/api-reference/v1-workflow-generation/generate-headless). ## Query Parameters The specific run to inspect. Defaults to the workflow's current (or most recent) run. ## Headers Your API authentication key ## Response The workflow ID. The run ID. The current run status. See [Run statuses](#run-statuses) below. Progress from 0 to 1 — the same progress you'd see in the Opus builder UI. Reaches `1.0` once finished, and may be `null` in the first seconds of a run. Your prompt. The run title. How the run was started (e.g., `headless_trigger`). Whether the generation session is still live. ISO 8601 timestamp of when the run started. ISO 8601 timestamp of the most recent activity on the run. Time elapsed since the run started, in milliseconds. The AI agents working on your run. Number of agents currently running. Number of agents that have finished. Number of agents that failed. Count of agents keyed by status (e.g., `{ "completed": 5, "running": 2 }`). Live snapshot of what the agents are doing right now. Whether any agent is currently working. Number of agents actively working. Per-agent detail for the agents currently working. Number of tasks queued or in progress. Whether the master agent is evaluating results. Every task the agents performed. The task ID. The agent's specialty (e.g., `architect`). The name of the agent that ran the task. The instance ID of the agent that ran the task. Task status: `running`, `completed`, `failed`, `cancelled`, or `skipped`. Which attempt this was for the task. A short summary of the task's result. Total number of tasks across all agents. ## Run statuses | Status | Meaning | Terminal | | - | - | - | | `received` | Queued, about to start | | | `processing` | Agents are building | | | `completed` | Finished successfully | ✅ | | `partial` | Finished, but some steps need your attention | ✅ | | `cancelled` | Stopped (by you, or by the run time limit) | ✅ | | `irrelevant` | The prompt didn't describe a buildable workflow | ✅ | ## Errors `workflowId` is not a valid UUID. Missing, invalid, or expired API key, or the key's user is no longer a member of the organization. The key's user lacks the **Workflow: Read** permission in the workflow's workspace. No run found for this workflow, or an unknown `runId` was provided. ```bash cURL theme={null} curl --request GET \ --url 'https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID}/run?runId={YOUR_RUN_ID}' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' ``` ```python Python theme={null} import requests workflow_id = "{YOUR_WORKFLOW_ID}" url = f"https://operator.opus.com/api/v1/workflow/{workflow_id}/run" headers = {"x-service-key": "{YOUR_SERVICE_KEY}"} params = {"runId": "{YOUR_RUN_ID}"} # optional — defaults to the current run response = requests.get(url, headers=headers, params=params) run = response.json() print(f"Status: {run['status']}") print(f"Progress: {run['progress']}") print(f"Tasks: {run['task_count']}") ``` ```javascript JavaScript theme={null} const workflowId = "{YOUR_WORKFLOW_ID}"; const response = await fetch( `https://operator.opus.com/api/v1/workflow/${workflowId}/run?runId={YOUR_RUN_ID}`, { method: "GET", headers: { "x-service-key": "{YOUR_SERVICE_KEY}", }, } ); const run = await response.json(); console.log(`Status: ${run.status}`); console.log(`Progress: ${run.progress}`); console.log(`Tasks: ${run.task_count}`); ``` ```json 200 Response theme={null} { "workflow_id": "{WORKFLOW_ID}", "run_id": "{RUN_ID}", "status": "processing", "progress": 0.4231, "text": "{YOUR_PROMPT}", "display_name": "{RUN_TITLE}", "origin": "headless_trigger", "room_active": true, "started_at": "2026-07-27T06:30:01+00:00", "last_activity_at": "2026-07-27T06:31:11+00:00", "elapsed_ms": 70123, "instances": { "running": 2, "done": 5, "failed": 0, "by_status": { "completed": 5, "running": 2 }, "live": { "busy": true, "working_agents": 2, "working_agents_detail": [], "pending_running_tasks": 1, "master_evaluating": false } }, "tasks_by_agent": [ { "task_id": "{TASK_ID}", "specialty": "architect", "worker_name": "{WORKER_NAME}", "worker_instance_id": "{WORKER_INSTANCE_ID}", "status": "completed", "attempt": 1, "result_summary": "{RESULT_SUMMARY}" } ], "task_count": 7 } ``` # Get Workflow Details Source: https://developer.opus.com/api-reference/v1-workflow-generation/get-workflow-details GET https://operator.opus.com/api/v1/workflow/{workflowId} Retrieve the workflow object — name, status, nodes and edges Before you can execute a case, you must know what inputs the workflow expects. This endpoint returns the workflow object: its name, status, and the full node/edge graph. The workflow's input definitions live on the **input node**: look up `nodes[workflowInputNodeId].input_schema.schema` to get the variable names and types you need for the [Execute Case](/api-reference/v1-case/execute-case) `payload`. By default, the response describes the latest version of the workflow. To inspect a specific historical version, pass one of the three version selectors as a query parameter. When more than one selector is supplied, they resolve in this order of priority: 1. `workflowVersionId` — the version UUID 2. `version` — the semantic version, `.` 3. `workflowVersionNumber` — the sequential version number ## Path Parameters The unique identifier of the workflow to retrieve details for ## Query Parameters Specific workflow version UUID. Highest priority — takes precedence over `version` and `workflowVersionNumber` when more than one is supplied. Semantic workflow version as `.`, for example `2.1`. A leading `v` is accepted and stripped (`v2.1` is the same as `2.1`). Both components must be integers, and the value is sent as a string — `1.10` and `1.1` are different versions. Sequential workflow version number to retrieve. Lowest priority. Omit all three selectors to use the latest version. ## Headers Your API authentication key ## Response The workflow ID The workflow version ID this object represents The workflow version number this object represents The latest version number of the workflow Workflow name Workflow description Validity status of the workflow Active status of the workflow ID of the workflow input node — its entry in `nodes` carries the input schema for [Execute Case](/api-reference/v1-case/execute-case) ID of the workflow output node — its entry in `nodes` defines the output variables returned by [Get Case Results](/api-reference/v1-case/get-case-results) IDs of the starting nodes IDs of the ending nodes The workflow nodes keyed by node ID. Node objects use snake\_case keys — the input node's `input_schema.schema` maps variable names to their definitions (`type`, `display_name`, `type_definition`, …). The workflow edges keyed by edge ID The organisational layer: named boxes grouping steps, each with an owner, duration estimate and review status. Keyed by section ID. Open object — the workflow model owns this shape and new fields appear without an API version bump, so read defensively. The annotation layer: canvas notes keyed by note ID. Open object. Design lifecycle stage. One of `interview`, `generating`, `rewire`, or `build`. Workflows created before the design flow, and all non-Discovery creations, read as `build`. The [Discovery](/api-reference/v1-discovery/discovery-introduction) approver who owns the design flow, as `{id, name, imgSrc}`. `null` outside the design flow. ISO timestamp of the workflow's most recent execution. `null` if never run. ## Errors `version` is not in `.` (or `v.`) form, or a selector is otherwise malformed. Missing, invalid, or expired API key. The workflow does not exist, or it has no version matching the selector. ## Supported Data Types Variables in `nodes[*].input_schema` and `nodes[*].output_schema` use the Opus type system. For the full list of types, nested `type_definition` shapes and date formats, see [Variable Schemas](/api-reference/v1-workflow-generation/variable-schemas#supported-data-types). ```bash cURL theme={null} # Latest version curl --request GET \ --url https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID} \ --header 'x-service-key: {YOUR_SERVICE_KEY}' # Pinned to a specific version number curl --request GET \ --url 'https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID}?workflowVersionNumber=3' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' # Pinned to a specific version UUID curl --request GET \ --url 'https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID}?workflowVersionId={WORKFLOW_VERSION_ID}' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' # Pinned to a semantic version curl --request GET \ --url 'https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID}?version=2.1' \ --header 'x-service-key: {YOUR_SERVICE_KEY}' ``` ```python Python theme={null} import requests url = "https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID}" headers = {"x-service-key": "{YOUR_SERVICE_KEY}"} # Latest version response = requests.get(url, headers=headers) # Or pin to a specific version # response = requests.get(url, headers=headers, params={"workflowVersionNumber": 3}) # response = requests.get(url, headers=headers, params={"workflowVersionId": "{WORKFLOW_VERSION_ID}"}) # response = requests.get(url, headers=headers, params={"version": "2.1"}) print(response.json()) ``` ```javascript JavaScript theme={null} // Latest version const response = await fetch( "https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID}", { method: "GET", headers: { "x-service-key": "{YOUR_SERVICE_KEY}", }, } ); // Or pin to a specific version // const url = new URL("https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID}"); // url.searchParams.set("workflowVersionNumber", "3"); // const response = await fetch(url, { headers: { "x-service-key": "{YOUR_SERVICE_KEY}" } }); const data = await response.json(); console.log(data); ``` ```json 200 Response theme={null} { "workflowId": "{WORKFLOW_ID}", "workflowVersionId": "{WORKFLOW_VERSION_ID}", "workflowVersionNumber": 3, "latestVersionNumber": 3, "name": "Quarterly Report Processor", "description": "Summarizes quarterly financial reports", "validityStatus": "valid", "activeStatus": "active", "workflowInputNodeId": "{INPUT_NODE_ID}", "workflowOutputNodeId": "{OUTPUT_NODE_ID}", "startingNodeIds": ["{INPUT_NODE_ID}"], "endingNodeIds": ["{OUTPUT_NODE_ID}"], "nodes": { "{INPUT_NODE_ID}": { "id": "{INPUT_NODE_ID}", "name": "Workflow Input", "input_schema": { "schema": { "{VARIABLE_NAME_1}": { "display_name": "{DISPLAY_NAME}", "allowed_types": [{ "type": "str", "type_definition": null }] } } } } }, "edges": { "{EDGE_ID}": { "from_node_id": "{INPUT_NODE_ID}", "to_node_id": "{OUTPUT_NODE_ID}" } }, "sections": {}, "notes": {}, "designStage": "build", "designOwner": null, "lastRun": "2026-08-01T14:32:11Z" } ``` # Human Node Source: https://developer.opus.com/api-reference/v1-workflow-generation/human-node Pause a workflow for a person to act — the human_task handler class and its process object A human node (`"type": "human"`) pauses the workflow and waits for a person. It has a single handler class, `human_task`. Use this page when building `nodes` for [Create a Workflow](/api-reference/v1-workflow-generation/create-workflow) or [Update a Workflow](/api-reference/v1-workflow-generation/update-workflow). A case that reaches a human node moves to the `WAITING` status until the task is completed — see [Get Case Status](/api-reference/v1-case/get-case-status). ## Process Fields What the person needs to do. This is the entire process object — a human task has no model, no prompts and no tools. Write it for the person who will open the task, not for Opus. What the task takes in and hands back is defined by the node's `input_schema` and `output_schema` instead — see [Variable Schemas](/api-reference/v1-workflow-generation/variable-schemas). ## Example ```json human node theme={null} { "id": "{NODE_ID}", "name": "Approve Refund", "type": "human", "handler_class": "human_task", "process": { "instructions": "Review the refund request and the attached receipt. Approve if the amount matches the receipt and the request is within 30 days of purchase; otherwise reject with a reason." } } ``` Whether a human task is carried out inside Opus or somewhere else is a **design-view setting, not a process field**, and it cannot be set through the create or update endpoints. Configure it in the [Builder](/guides/builder). ## Related How human tasks appear and behave in the Opus product Human and agentic review steps # Integration Node Source: https://developer.opus.com/api-reference/v1-workflow-generation/integration-node Call an external system as a workflow step — the integration handler class and its process object An integration node (`"type": "integration"`) calls out to an external system. It has a single handler class, `integration`, and its `process` is an **action reference** — it names the action to run rather than carrying its configuration inline. Use this page when building `nodes` for [Create a Workflow](/api-reference/v1-workflow-generation/create-workflow) or [Update a Workflow](/api-reference/v1-workflow-generation/update-workflow). ## Process Fields The action to run — what this step does on the external system, such as `Send Message` or `Create Row`. What the action does. The integration the action belongs to. Integration display name What the integration connects to Integration icon The vendor or system behind the integration. Provider display name — for example `Slack`, `Google` What the provider is Provider icon The nesting mirrors how integrations are organised in Opus: a **provider** is the vendor, an **integration** is a connection to it, and an **action** is one operation on that integration. ## Example ```json integration node theme={null} { "id": "{NODE_ID}", "name": "Post To Slack", "type": "integration", "handler_class": "integration", "process": { "name": "Send Message", "description": "Post a message to a channel", "integration": { "name": "Slack", "description": "Team messaging", "provider": { "name": "Slack", "description": "Slack Technologies" } } } } ``` Credentials are never part of the node. They are attached to the integration itself — see [Create a Credential](/api-reference/v1-integration/create-credential). ## Related Create providers, integrations and credentials through the API Pre-built connectors available in Opus # Node Process Types Source: https://developer.opus.com/api-reference/v1-workflow-generation/node-process-types How a node's handler class determines the shape of its process object When you send `nodes` to [Create a Workflow](/api-reference/v1-workflow-generation/create-workflow) or [Update a Workflow](/api-reference/v1-workflow-generation/update-workflow), each node carries three fields that must agree with one another: * **`type`** — what kind of step this is (`agent`, `code`, `human`, `integration`, …) * **`handler_class`** — which variety of that step * **`process`** — the step's configuration, whose shape is **determined by `handler_class`** The `process` object has no type tag of its own. Opus reads `handler_class` to decide which shape to validate `process` against, so sending the right fields under the wrong `handler_class` fails validation. ## Which Process Goes With Which Node | Node `type` | `handler_class` | `process` shape | Reference | | - | - | - | - | | `agent` | `agent_basic` | Blueprint + model | [Agent Node](/api-reference/v1-workflow-generation/agent-node) | | `agent` | `agent_custom` | Your own prompts | [Agent Node](/api-reference/v1-workflow-generation/agent-node) | | `agent` | `agent_advanced` | Blueprint + tools | [Agent Node](/api-reference/v1-workflow-generation/agent-node) | | `code` | `code` | Python source | [Code Node](/api-reference/v1-workflow-generation/code-node) | | `human` | `human_task` | Instructions | [Human Node](/api-reference/v1-workflow-generation/human-node) | | `integration` | `integration` | Action reference | [Integration Node](/api-reference/v1-workflow-generation/integration-node) | `input` and `output` nodes take **no `process`** — they carry only schemas. Opus adds one of each automatically when you create a workflow without supplying `nodes`. `sub_workflow`, `meta_node`, `obfuscate` and `deobfuscate` nodes are not currently supported through the API. Build them in the [Builder](/guides/builder) instead. ## Rules That Apply To Every Node `nodes` and `edges` are objects keyed by ID, not arrays. Each key must be identical to the `id` inside the object it holds. ```json theme={null} "nodes": { "3fa85f64-5717-4562-b3fc-2c963f66afa6": { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "name": "Summarize Report", "type": "agent" } } ``` The top-level body of the create and update requests is camelCase (`activeStatus`, `orgUnitIds`), but everything inside a node or edge is snake\_case (`input_schema`, `from_node_id`, `handler_class`). This is deliberate: nodes and edges are forwarded to the Opus workflow executor exactly as you send them. Opus checks the node's outer fields, then the executor validates `process` against the model named by `handler_class`. A malformed `process` is rejected there, so a `400` can describe a field you sent inside `process` rather than one at the top level. ## Schemas Are Separate From Process Every step node also carries `input_schema` and `output_schema`, which describe the variables flowing in and out. Those are the same shape on every node type regardless of `handler_class` — see [Variable Schemas](/api-reference/v1-workflow-generation/variable-schemas). `process` says *how the step does its work*. The schemas say *what it takes in and hands on*. A node needs both. ## Choosing An Agent Class Agent is the only node type with more than one class, and the choice is the most consequential one you'll make: You describe the goal; Opus writes the agent. Best when you want the outcome specified and the prompting handled for you. You supply the system and user prompts verbatim. Best when you need exact control over wording. A Basic agent that can call other agents and code utilities as tools. Best for multi-step work. See [Agent Node](/api-reference/v1-workflow-generation/agent-node) for the full field-by-field comparison. # Restore a Workflow Source: https://developer.opus.com/api-reference/v1-workflow-generation/restore-workflow POST https://operator.opus.com/api/v1/workflow/{workflowId}/restore Un-archive a workflow, returning it to listings Un-archive a workflow, returning it to listings. This is the inverse of [Archive a Workflow](/api-reference/v1-workflow-generation/archive-workflow). Requires the **Workflow: Full** permission on the workflow. Restoring is idempotent in the same way archiving is: restoring a workflow that is not archived succeeds and changes nothing. ## Path Parameters The ID of the workflow to restore ## Headers Your API authentication key ## Response The workflow ID that was restored — the same ID you supplied in the path Archive status after the call. Always `false` on a 2xx response. This is the mirror of [Archive a Workflow](/api-reference/v1-workflow-generation/archive-workflow), so you can read the result of an archive and a restore the same way. `archivedAt` and `archivedBy` are deliberately **not** returned here — on a restore they are cleared by definition, and returning two always-null fields would suggest "unknown" rather than "not applicable". ## Errors Missing, invalid, or expired API key. No access to this workflow. The workflow does not exist. ```bash cURL theme={null} curl --request POST \ --url https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID}/restore \ --header 'x-service-key: {YOUR_SERVICE_KEY}' ``` ```python Python theme={null} import requests response = requests.post( "https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID}/restore", headers={"x-service-key": "{YOUR_SERVICE_KEY}"}, ) print(response.json()) ``` ```javascript JavaScript theme={null} const response = await fetch( "https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID}/restore", { method: "POST", headers: { "x-service-key": "{YOUR_SERVICE_KEY}" }, } ); const data = await response.json(); console.log(data); ``` ```json 201 Response theme={null} { "workflowId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "isArchived": false } ``` # Update a Workflow Source: https://developer.opus.com/api-reference/v1-workflow-generation/update-workflow PUT https://operator.opus.com/api/v1/workflow/{workflowId} Replace a workflow's definition and mint a new version Replace the workflow with the definition in the body and mint a new version. Requires the **Workflow: Full** permission on the workflow. **This is a replace, not a merge.** Nodes and edges absent from the body are removed from the new version — so send the whole workflow, not just the parts you changed. Fetch the current definition with [Get Workflow Details](/api-reference/v1-workflow-generation/get-workflow-details) first, modify it, then send it back in full. The change is recorded as a single API-update entry in the workflow's version history. Earlier versions are untouched and stay retrievable by version number or ID. ## Path Parameters The ID of the workflow to update ## Headers Your API authentication key ## Body Parameters Workflow name Workflow description Workflow nodes keyed by node ID, in the same shape as [Create a Workflow](/api-reference/v1-workflow-generation/create-workflow#body-parameters). Each map key must equal the `id` of the node it holds. Replaces the existing set — a node absent from this map is removed from the new version. A node's `handler_class` determines the shape of its `process` — see [Node Process Types](/api-reference/v1-workflow-generation/node-process-types). For `input_schema` and `output_schema`, see [Variable Schemas](/api-reference/v1-workflow-generation/variable-schemas). Workflow edges keyed by edge ID, in the same shape as [Create a Workflow](/api-reference/v1-workflow-generation/create-workflow#body-parameters). Each map key must equal the `id` of the edge it holds, and `from_node_id` and `to_node_id` must name nodes present in `nodes`. Replaces the existing set — an edge absent from this map is removed from the new version. Workflow active status. One of `active` or `inactive`. Workflow validity status. One of `valid` or `invalid`. ## Response The ID of the version this update created The version number this update created Major component of the new version. `null` if the workflow is not semantically versioned. Minor component of the new version. `null` if the workflow is not semantically versioned. How the version was classified. One of `major` or `minor`. An API update always classifies as `major`, because a single call can rewrite the whole workflow. ## Errors The workflow definition is malformed. Missing, invalid, or expired API key. No access to this workflow. The workflow does not exist. ```bash cURL theme={null} curl --request PUT \ --url https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID} \ --header 'x-service-key: {YOUR_SERVICE_KEY}' \ --header 'Content-Type: application/json' \ --data '{ "name": "Quarterly Report Processor", "description": "Summarizes quarterly financial reports", "activeStatus": "active", "nodes": { "...": "the complete node map" }, "edges": { "...": "the complete edge map" } }' ``` ```python Python theme={null} import requests BASE = "https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID}" headers = {"x-service-key": "{YOUR_SERVICE_KEY}"} # Read the current definition, change one thing, send the whole thing back. current = requests.get(BASE, headers=headers).json() response = requests.put( BASE, headers=headers, json={ "name": "Quarterly Report Processor (v2)", "description": current["description"], "nodes": current["nodes"], "edges": current["edges"], "activeStatus": "active", }, ) print(response.json()) ``` ```javascript JavaScript theme={null} const base = "https://operator.opus.com/api/v1/workflow/{YOUR_WORKFLOW_ID}"; const headers = { "x-service-key": "{YOUR_SERVICE_KEY}" }; // Read the current definition, change one thing, send the whole thing back. const current = await (await fetch(base, { headers })).json(); const response = await fetch(base, { method: "PUT", headers: { ...headers, "Content-Type": "application/json" }, body: JSON.stringify({ name: "Quarterly Report Processor (v2)", description: current.description, nodes: current.nodes, edges: current.edges, activeStatus: "active", }), }); const data = await response.json(); console.log(data); ``` ```json 200 Response theme={null} { "workflowVersionId": "{WORKFLOW_VERSION_ID}", "workflowVersionNumber": 4, "majorVersion": 2, "minorVersion": 0, "versionLabel": "major" } ``` # Variable Schemas Source: https://developer.opus.com/api-reference/v1-workflow-generation/variable-schemas How a node declares the variables it takes in and hands on Every step node carries an `input_schema` and an `output_schema`. They have the same shape on every node type, regardless of `handler_class`. `process` says *how* a step does its work. The schemas say *what it takes in and hands on*. A node needs both. Use this page when building `nodes` for [Create a Workflow](/api-reference/v1-workflow-generation/create-workflow) or [Update a Workflow](/api-reference/v1-workflow-generation/update-workflow). ## Schema The variables, keyed by variable ID. Each value is a [Variable Definition](#variable-definition). Whether new variables may be added to this schema later. ## Variable Definition Variable ID. Must match the key this definition is stored under. The name your code and prompts refer to Human-readable label. Defaults to an empty string. The types this variable may hold — **at least one**. Each entry is an [Allowed Type](#allowed-type). Which of `allowed_types` is currently active. When set it **must** name a type present in `allowed_types`, or the request is rejected. When omitted, the first entry in `allowed_types` is used. Value used when none is supplied What this variable holds Whether the variable may be null Permitted values, when the variable is a fixed choice. Defaults to empty. Extra key/value context, each `{ variable_name, value, description }`. Defaults to empty. Fields that may not be edited later. Values are field names such as `variable_name`, `display_name`, `description`, `is_nullable`, `tags`, `options`, `allowed_types`. Whether the variable may be removed ## Allowed Type One of the [supported data types](#supported-data-types). Defaults to `str`. The inner shape, for types that have one. What it holds depends on `type`: * **`object`** — a map of variable name to a nested variable definition * **`array`** — a single nested variable definition, describing every element * **`date`** — a [date format](#date-formats) string Leave it unset for scalar types. Whether `type_definition` is enforced at runtime Functions the executor applies to resolve the value at runtime. Currently `now` is supported, for date variables. ## Supported Data Types | Type | Description | Example Value | | - | - | - | | `str` | Text string | `"Hello World"` | | `int` | Whole number | `42` | | `float` | Decimal number | `45.8` | | `bool` | Boolean | `true` or `false` | | `date` | Date string — pair with a [date format](#date-formats) | `"2025-11-09"` | | `file` | A single file | `"https://files.opus.com/..."` | | `array` | List of values — describe elements with `type_definition` | `["item1", "item2"]` | | `object` | Nested object — describe fields with `type_definition` | `{"key": "value"}` | | `json_string` | JSON encoded as a string | `"{\"key\":\"value\"}"` | | `binary` | Binary data | — | | `node` | A reference to another node | — | **There is no `array_files` type.** Multiple files are an `array` whose `type_definition` is a variable definition with a single allowed type of `file`. ### Date Formats When `type` is `date`, `type_definition` names the format: | Format | Example | | - | - | | `%Y-%m-%d` | 2025-07-23 | | `%Y-%m-%dT%H:%M` | 2025-07-23T15:30 | | `%m/%d/%Y` | 07/23/2025 | | `%m-%d-%Y` | 07-23-2025 | | `%m.%d.%Y` | 07.23.2025 | | `%d/%m/%Y` | 23/07/2025 | | `%d-%m-%Y` | 23-07-2025 | | `%d.%m.%Y` | 23.07.2025 | | `%B %d, %Y` | July 23, 2025 | | `%b %d, %Y` | Jul 23, 2025 | | `%d %B %Y` | 23 July 2025 | | `%Y.%m.%d` | 2025.07.23 | | `%Y-%j` | 2025-204 (day of year) | | `%Y年%m月%d日` | 2025年07月23日 | | `UNIX` | 172169280 | ## Connecting Variables Between Nodes An edge says two nodes are connected. A **mapping** says which variable flows across it. Mappings live on the node's `mappings` field, keyed by the receiving variable's ID. Where the value comes from. One of `input`, `output`, `env` or `node`. ID of the node the value comes from Path to the value within the origin — use dotted notation to reach into an `object` Fallback mappings, keyed the same way, used when the primary does not resolve ```json mappings theme={null} "mappings": { "{RECEIVING_VARIABLE_ID}": { "origin": "output", "origin_id": "{UPSTREAM_NODE_ID}", "variable_path": "summary" } } ``` ## Fixed Values To pin a variable to a constant rather than map it from another node, use `set_values`: Fixed input values, keyed by variable ID. Each is `{ value, type }`. Fixed output values, keyed by variable ID. Each is `{ value, type }`. ## Example A node taking one string input and returning an array of objects: ```json theme={null} { "input_schema": { "schema": { "{VAR_ID_1}": { "id": "{VAR_ID_1}", "variable_name": "report_text", "display_name": "Report Text", "description": "The full quarterly report", "allowed_types": [{ "type": "str" }], "is_nullable": false } }, "variable_addition_allowed": true }, "output_schema": { "schema": { "{VAR_ID_2}": { "id": "{VAR_ID_2}", "variable_name": "findings", "display_name": "Findings", "allowed_types": [ { "type": "array", "type_definition": { "id": "{VAR_ID_3}", "variable_name": "finding", "allowed_types": [ { "type": "object", "type_definition": { "title": { "id": "{VAR_ID_4}", "variable_name": "title", "allowed_types": [{ "type": "str" }] } } } ] } } ] } }, "variable_addition_allowed": true } } ``` # Introduction Source: https://developer.opus.com/api-reference/v1-workflow-generation/workflow-generation-introduction Create, read, update, archive and restore Opus workflows through the API ## Overview A **workflow** is the unit of automation in Opus: a graph of steps — agents, code, human tasks and integrations — that runs against the inputs you give it. The Workflow API manages the full lifecycle of a workflow with no browser session required. You can create one, read its definition, replace it, archive it and restore it. Once a workflow exists, you run it as a [case](/api-reference/v1-case/case-introduction). ## Base URL All API requests should be made to the following base URL: ```text theme={null} https://operator.opus.com/api/v1/workflow/ ``` ## Authentication All API endpoints require authentication with your Opus API key, sent in the `x-service-key` header. ```text theme={null} x-service-key: ``` The key is also accepted as a Bearer token (`Authorization: Bearer `). Your key determines your identity: the acting user, your organization, and the workspaces you can target. Each endpoint additionally requires the listed workflow permission in the target workspace. A request with a missing, invalid, or expired key returns `401`. Keys are also rate limited — sustained bursts return `429`. Your API key is a unique, secret credential. Store it securely and never expose it in client-side code. ## Two Ways To Build A Workflow `POST /workflow` with the nodes and edges you want. You control the graph exactly. Best when you already know the steps, or you are generating workflows from your own system. `POST /workflow/generate` with a description in plain language. Opus AI agents design and build the graph, and you poll the run until it finishes. Both produce an ordinary workflow — the same `workflowId`, readable with the same [Get Workflow Details](/api-reference/v1-workflow-generation/get-workflow-details) call, editable with the same [Update a Workflow](/api-reference/v1-workflow-generation/update-workflow) call. The choice is only about how the first version gets written. ## Lifecycle [Create a workflow](/api-reference/v1-workflow-generation/create-workflow) directly, or [generate one](/api-reference/v1-workflow-generation/generate-headless) from a prompt. Either way you get a `workflowId`. [Get Workflow Details](/api-reference/v1-workflow-generation/get-workflow-details) returns the full definition, including the input schema you need to run it. [Update a Workflow](/api-reference/v1-workflow-generation/update-workflow) replaces the definition and mints a new version. Earlier versions stay retrievable. Execute the workflow as a [case](/api-reference/v1-case/case-introduction). [Archive](/api-reference/v1-workflow-generation/archive-workflow) takes a workflow out of listings; [Restore](/api-reference/v1-workflow-generation/restore-workflow) brings it back. ## Versioning Every update mints a new version rather than editing in place, so a workflow is a history, not a single document. * [Update a Workflow](/api-reference/v1-workflow-generation/update-workflow) is a **replace** — send the whole definition, because anything absent is removed from the new version. * [Get Workflow Details](/api-reference/v1-workflow-generation/get-workflow-details) reads the latest version by default, and any earlier one by version UUID, semantic version or version number. * A workflow with an **active version cannot be archived** — deactivate it first. ## Defining Nodes And Edges When you send a workflow definition, each node's `handler_class` determines the shape of its `process`, and every node carries an input and output schema. Which process object goes with which node type How a node declares the variables it takes in and hands on ## Generation Runs These notes apply only to [Generate Workflow](/api-reference/v1-workflow-generation/generate-headless), not to the other endpoints. **One run at a time** per workflow. Starting a second run while one is active returns `409`. [Cancel the current run](/api-reference/v1-workflow-generation/cancel-run) or wait for it to finish. * **Polling**: Progress updates continuously; polling every 3–10 seconds is plenty. * **Time limit**: Runs that exceed **25 minutes** are cancelled automatically. * **Files**: Attach only files your user can access. A file that can't be read is skipped with a note in the run's task results rather than failing the run. ## Available Endpoints ### Managing Workflows Create a workflow, optionally pre-populated with nodes and edges Retrieve the workflow object — name, status, nodes and edges Replace a workflow's definition and mint a new version Archive a workflow, removing it from listings Un-archive a workflow, returning it to listings ### Generating Workflows Start a new workflow generation run from a prompt Poll a generation run until it completes Stop an in-progress generation run # Builder Source: https://developer.opus.com/guides/builder The visual workflow interface for designing, configuring, and testing automation workflows in Opus. The Builder is Opus's visual workflow editor and preview environment. It provides a visual interface to drag-and-drop tasks, wire variable mappings, configure task parameters, and test execution with real-time feedback before activating workflows for production use. ## Overview The Builder is where you design, configure, and test workflows before deploying them to production. Here you: * **Create workflows** by adding and connecting tasks in the visual Builder * **Configure tasks** with inputs, outputs, and task-specific parameters * **Test with previews** that simulate real execution with live state feedback * **Set up integrations** with external systems through Opus's Integration Marketplace, or connect with any external API using the External Service task Opus's Integration Marketplace supports 3,500+ integrations with over 36,000 different actions. * **Validate before activation** to catch errors early and reduce production issues Think of the Builder as both your design tool and your testing environment. Investing time in thorough previews here pays dividends in fewer job failures later. ## Builder Fundamentals ### Tasks And Connections Workflows are built from two simple elements: | Element | Description | | - | - | | **Tasks** | Individual steps that perform specific actions (AI processing, data import, human review, etc.) | | **Connections** | Lines between tasks that define how data flows and the order steps run | Each task has inputs (data it receives) and outputs (data it produces). When you connect two tasks, you're passing data from one step to the next and telling the workflow which steps must finish before others can begin. ### Adding Tasks Click the **+** button in the Builder or drag from the task palette to add tasks. Available task types include: * **Opus Agent**: Maximum capability agent that takes a natural language task description and intelligently figures out how to accomplish it * **Custom Agent**: Simple one-shot LLM interaction from popular providers (OpenAI, Anthropic, DeepSeek, etc.) * **Opus Human Task**: Assign tasks requiring human input * **Decision Agent**: Automated routing based on conditions defined via natural language or logical expressions * **Human Decision Agent**: Same as Decision Agent, but a human evaluates the conditions and makes the routing decision * **Opus Code** Expert: Execute custom Python code within your workflow Quality assurance through human oversight or AI-powered validation. * **Human Review**: Pauses workflows for accept/reject decisions with optional editing—ideal for compliance checks and quality gates requiring human judgment. * **Agentic Review**: Uses AI to validate outputs against defined criteria, with optional auto-correction for scalable quality assurance without human bottlenecks. Run another workflow as a sub-workflow, enabling modular workflow composition and reuse across your organization. Connect to external services through Opus's **Integration Marketplace**, which provides **3,500+ pre-built connectors** with over **36,000 different actions** for cloud storage, productivity tools, databases, CRMs, and more. * **Import Data**: Pull data from connected services (Google Drive, S3, etc.) * **Export Data**: Send results to external systems (Sheets, Slack, etc.) * **Opus Text Extraction**: Extract text from documents and images using OCR * **External Service** Intermediate: Connect to any external REST API via a variety of authentication options including Basic Auth, Bearer Auth, Header Auth, JWT, or No Auth. ### Connecting Tasks To connect tasks: 1. Click on an output port of the source task 2. Drag to an input port of the destination task 3. Release to create the edge The Builder enforces valid connections—you cannot create circular dependencies or connect incompatible variable types. ## Task Configuration ### Variables Each task defines typed input and output variables. For example: ``` Input Variables: - document_text (Text): The content to process - max_length (Number): Maximum output length Output Variables: - summary (Text): Generated summary - confidence (Number): Confidence score ``` When configuring a task, you can: * **Link** variables to upstream outputs (auto-populated from connected tasks) * **Set static values** for configuration parameters * **Define new variables** that downstream tasks can consume ## Builder Features The Builder provides essential features for managing your workflow: ### Action Center The **Action Center** is located at the top center of the Builder and displays all pending action items that must be resolved before you can run your workflow. * Shows issues like missing connections, unconfigured variables, and validation errors * The **Auto-fix** button lets Opus AI automatically resolve common configuration issues * When the Action Center shows "No action items," your workflow is ready to test Use Auto-fix liberally—it can save significant time by intelligently resolving configuration issues that would otherwise require manual intervention. ### Auto-Link The **auto-link** feature uses AI to intelligently connect variables between tasks: * Available inside variable configuration panels and on the input panel for Opus Agent * Click the auto-link button to have Opus map matching inputs and outputs * Saves time when connecting multiple variables across complex workflows ### Clear Saved Data The Builder caches data from completed runs to save costs and improve iteration speed. To perform a completely fresh run where all data is recalculated: * Click the **Clear Saved Data** button (located to the right of the Run Workflow button) * This clears all cached results from previous runs * Then click Run Workflow to execute all tasks from scratch ### Generate Variable Opus supports a **Generate Variable** feature that creates mock data for your input variables: * Click the **Generate Variable** button in the Workflow Input task * Opus auto-generates sample values based on variable types and descriptions * Quickly test workflows without manually entering data ### Tidy Up Click the **Tidy Up** button to automatically format and arrange your workflow tasks in a clean, organized layout. This feature: * Aligns tasks in a logical flow from left to right * Adjusts spacing for optimal readability * Organizes parallel branches neatly This is especially helpful as workflows grow more complex or after making significant edits. ### Opus AI Assist **Opus AI Assist** is the inline AI editing assistant that lets you modify your workflow using natural language. Located at the bottom left of the Builder, it allows you to describe changes in plain English and have Opus propose edits to your existing workflow. **How to use:** Click the **Ask Opus AI Assist** button at the bottom left of the Builder. Enter a description of the edits you want to make in the prompt field. For example: * "Add a Human Review task before the final email is sent" * "Route all high-risk outputs to a separate branch with a review" * "Change this agent to use a different model but keep the same inputs and outputs" Opus AI generates a **Workflow Proposals** plan showing the proposed changes to your workflow. Review the suggested edits in the modal. Click **Confirm** to apply the changes to your workflow, or close the modal to discard them. **What Opus AI Assist can do:** * Add, delete, or move tasks * Rewire connections between tasks * Adjust variable mappings * Update task configurations Changes are only applied after you review and confirm them in the Workflow Proposals modal. You stay in control of your workflow at all times. ## Running Workflows The Builder includes a dedicated testing environment for running workflows with real-time feedback before activation. ### Executing A Test Run Check the Action Center and ensure all action items are resolved. Use **Auto-fix** to let Opus resolve them with AI, or fix them manually. Enter values for all variables in the Workflow Input task. Use realistic data that represents expected production inputs, or use the **Generate Variable** feature to create mock data. For file inputs, the maximum upload size is **10 MB** per file. Click **Run Workflow**. The engine traverses your graph, executing tasks as their dependencies complete. Watch as tasks transition through states: * **Running**: Currently executing (blue, animated) * **Completed**: Successfully finished (green) * **Failed**: Error occurred (red with message) Click any task to inspect its outputs. Failed tasks show error details to help you debug. ### Caching And Clear Saved Data To save costs and improve iteration speed, the Builder caches data from completed runs: * When you run the workflow again, tasks with unchanged inputs use cached results instead of re-executing * This allows rapid iteration without incurring full execution costs To perform a completely fresh run where all data is recalculated: * Click the **Clear Saved Data** button (located to the right of the Run Workflow button) * Then click Run Workflow to execute all tasks from scratch ### Run Features | Feature | Description | | - | - | | **State animations** | Visual feedback shows which tasks are active, waiting, or complete | | **Stop control** | Abort long-running runs without getting stuck | | **Error surfacing** | Tasks with errors are surfaced directly in the graph | | **Success banner** | Clear confirmation when run completes without errors | | **Result caching** | Cached data speeds up subsequent runs and reduces costs | ## Related Resources Understand workflow lifecycle, states, and best practices. Learn how workflows execute as auditable jobs. Explore all available integrations and setup guides. Detailed documentation for each task type. # Jobs Source: https://developer.opus.com/guides/jobs Learn how to run workflows and track results in Opus. A Job is what happens when you run a workflow. You provide inputs, Opus runs through the workflow steps, and you get outputs. ## What Is A Job? When you run a workflow, you create a job. Here's what that means: | What you get | Why it matters | | - | - | | **Your inputs are saved** | You can always see what data you started with | | **Locked workflow version** | The job runs exactly the workflow you activated—later edits don't affect it | | **Results are stored** | Access your outputs anytime, even months later | | **Full history** | Everything is logged so you can review or audit later | Jobs are different from Builder previews. Jobs are production runs that are tracked and saved for future reference. ## Creating And Running Jobs ### From The UI Click **Jobs** in the sidebar, or click **New Job** from the workflow details page of any active workflow. If you started from the Jobs page, select an active workflow from the dropdown. This step is skipped if you started from a workflow details page. Fill in the required fields. These match the inputs you defined in your workflow. For file inputs, you can upload directly or pull from connected integrations. This depends on your workflow design. Click **Execute Job**. Track progress in the Jobs dashboard. You can see which steps are running and when they complete. ### From The API You can also start jobs programmatically. This is useful for running jobs on a schedule, automating recurring processes, or triggering workflows from your own applications. See the [API Reference](/api-reference/introduction) for full details. ## Job Status And Monitoring ### Status Indicators Jobs show clear status indicators as they run: * **In Progress**: Actively working through the workflow steps * **Completed**: Everything finished without errors * **Failed**: Something went wrong—you'll see which step failed and why ### Viewing Job Details On the Job Details page, you can see: * **Inputs**: What you provided when you started the job * **Outputs**: The results (if the job completed) * **Timeline**: When each step started and finished * **Errors**: What went wrong (if it failed) * **Audit log**: The complete record of everything that happened ## Error Handling ### Common Problems And Fixes **What happened**: Your connection to an external service (like Google or Slack) expired. **Fix**: Go to integrations settings, reconnect the service, and re-run the job. **Prevent it**: Test your integrations in Builder preview before activating. **What happened**: An external API blocked you for making too many requests. **Fix**: Wait a few minutes and try again. **Prevent it**: Space out your API calls or process data in smaller batches. **What happened**: You provided data in the wrong format (like text instead of a number). **Fix**: Check what type of input the workflow expects and provide the right format. **Prevent it**: Test your inputs in Builder preview before activating. **What happened**: You uploaded a file that exceeds the 10 MB size limit. **Fix**: Reduce the file size (compress, split, or remove unnecessary content) and try again. **Prevent it**: Check file sizes before uploading. The maximum file size for uploads is 10 MB per file. ### Where Errors Appear Errors are shown in three places on the Job Details page: 1. **On the failed step**: The specific step that failed is marked with an error message 2. **On the job**: The overall job shows as Failed with a summary 3. **In the audit log**: Full details for deeper investigation Start by finding which step failed, then read its error message. That usually tells you exactly what went wrong. ## Jobs And Subworkflows When your workflow calls another workflow: * The job runs both the main workflow and the sub-workflow * Both must be active and in the same workspace * You can see results from both in the job details ## Best Practices ### Before Running * **Make sure the workflow is active** — Draft workflows can't run jobs * **Test in Builder first** — Catch problems before running production jobs * **Check your integrations** — Make sure connections haven't expired ### While Running * **Watch for stuck jobs** — If a job seems frozen, check for errors * **Don't run duplicates** — Wait for a job to finish before starting another with the same inputs ### After Completion * **Check your results** — Make sure the outputs look right * **Review failures** — Use error details to fix problems in your workflow ## Related Resources Design the automation logic that jobs execute. Test workflows with previews before production jobs. Trigger and monitor jobs programmatically. Manage job access across your team. # Manhours Source: https://developer.opus.com/guides/manhours Understand how Opus measures and bills usage through Manhours. Manhours are Opus's unit of measurement for usage. They represent the work your jobs do. You're only charged when a job completes successfully—failed jobs don't cost anything. ## How Manhours Work | Term | What it means | | - | - | | **Estimate** | What Opus thinks the job will cost before it runs | | **Actual charge** | What you actually pay, based on what ran | | **Conditional paths** | If your workflow has branches, the estimate shows the most expensive path—but you only pay for the path that actually runs | Estimates are always worst-case. Your actual charge is often lower. ## When You're Charged ### Jobs You're only charged when a job completes successfully: | Job status | Charged? | | - | - | | Created | No | | Queued | No | | Running | No | | **Completed** | **Yes** | | Failed | No | If a job fails, you don't pay—so you can retry without worrying about double charges. ### Builder Activities Manhours are also consumed when: * **Running previews** in the Builder to test your workflows * **Using Prompt to Workflow** to generate workflows from natural language * **Using Opus AI Assist** to edit and modify workflows in the Builder ## Viewing Your Usage Every charge is logged with full details: * When it happened * Which workflow and workspace * How many Manhours were used * Your remaining balance * Who ran the job Find this log in **Organization settings → Plan & Usage → Usage**. ## Related Resources Learn how to run workflows and track results. Manage Manhour allocation across your organization. # Organization Source: https://developer.opus.com/guides/organization Manage your company's Opus account, billing, team members, and settings. Your organization is your company's home base in Opus. Everything flows from here—your subscription, your team members, and the rules that govern how your teams work. ## What Organizations Manage Pick your subscription, track your Manhours, and handle billing. Your plan determines which features your teams can use. Define review requirements, workflow policies, and caching behavior. Connect services once and make them available to all teams. ## Roles There are three roles at the organization level: | Role | What they can do | | - | - | | **Organization Admin** | Full access to everything—members, billing, settings, and all workspaces | | **Organization Billing** | Manage billing, view plans, and distribute Manhours | | **Workspace Member** | Access only the workspaces they've been added to | Organization roles and workspace roles are separate. ## Billing And Plans ### Your Subscription Manage your plan in **Organization Settings → Plan & Usage**: | What you can do | How it works | | - | - | | **Pick a plan** | Choose between Free and paid tiers | | **Track usage** | See how many Manhours you've used and how many you have left | | **Upgrade or downgrade** | Switch plans anytime—this starts a new billing cycle | | **Add more Manhours** | Buy extra credits if you're running low | ## Preferences ### Review Settings Set organization-wide defaults for how reviews work: * Balance between human oversight and AI assistance * Minimum review requirements for all workflows Find these in **Organization Settings → Preferences**. ### Policies Policies are organization-wide and govern workflow generation. * Require certain checks before workflows can go live * Set rules for specific types of tasks All workspaces in your organization will inherit these policies. ### Workflow caching Workflow caching improves workflow generation as it helps Opus's **Large Work Model (LWM)** learn from your workflows to make more accurate future generations. Turn caching on or off for your organization in **Organization Settings → Preferences**. If you enable Workflow Caching, you might need to disable certain Policy Checks. Opus will warn you when there's a conflict. ## Related Set up teams and manage access at the workspace level. Learn how to use API keys to run jobs from code. Understand how jobs work and consume Manhours. See all the services you can connect to. # Workflows Source: https://developer.opus.com/guides/workflows Learn how to build, manage, and run automated workflows in Opus. A Workflow is a step-by-step automated process. You connect different tasks together, and Opus runs them in order, passing data from one step to the next. Once you've built and activated a workflow, you can run it as many times as you want with different inputs—each run is called a Job. ## What Is A Workflow? Workflows are reusable automation templates that define: * **What** tasks to perform * **How** data flows between tasks (edges) * **When** each task runs (based on dependencies) Individual steps like AI processing, human reviews, data imports, and custom code. Connections that define how data moves between tasks and the order they run. Named inputs and outputs that carry data through the workflow. ## Workflow Lifecycle Every workflow goes through two states: | State | What it means | Can run jobs? | Can edit? | | - | - | - | - | | **Draft** | You're still building and testing | No | Yes | | **Active** | Ready for production use | Yes | No | Jobs can only run on active workflows. If you use sub-workflows, they must also be active and in the same workspace. ### Activating A Workflow Click **Activate** in the Builder after testing in preview mode. The workflow is now locked and ready to run jobs. Once activated, a workflow version is locked. Past job runs stay tied to the version they used, so your edits won't affect previous results. ## Workflow Structure Data moves through your workflow via connections between tasks: 1. **Connect outputs to inputs**: Link what one task produces to what the next task needs 2. **Automatic ordering**: Tasks wait for their inputs before running 3. **Required inputs**: A task won't start until all its required inputs are ready ## Running Workflows ### Two Ways To Run | Method | Where | When to use | | - | - | - | | **Preview** | In the Builder | Testing before you activate | | **Job** | Jobs page or API | Production runs with full tracking | ### Sub-Workflows The **Execute Workflow** task lets you run another workflow inside yours: * The sub-workflow's inputs and outputs connect to your main workflow * Both workflows must be active and in the same workspace Use sub-workflows to package complex logic into reusable pieces. This keeps your main workflow clean and avoids duplicating work. ## Example Workflows Opus includes a templates library with over 30,000 ready-to-use workflows. Click **[Templates](https://app.opus.com/app/workflow/create/templates)** in the left navbar to browse the collection. You can filter by industry to find workflows built for your specific use cases—a great way to learn how others structure quality workflows and get a head start on your own. ## Best Practices Add a check at the start to catch bad data before it causes problems downstream. Each task should do one thing well. Combining actions makes workflows harder to debug. Minimize dependencies so you can update tasks without breaking others. Don't combine review and action in one task. Keeping them separate aids debugging. Only emit data you need for monitoring. Too much output hides what's important. Run no more than 3 heavy tasks at once. Mix parallel and sequential steps. Use sub-workflows to split complex operations into smaller, reusable pieces. Validate credentials during Builder preview—don't wait until production. When accuracy matters, include Human Review tasks for accountability. ## Related Resources Learn how to design workflows in the visual editor. Execute workflows and monitor results. Detailed documentation on sub-workflow composition. Connect workflows to external systems. # Workspace Source: https://developer.opus.com/guides/workspace Team spaces where your workflows, jobs, and collaboration happen in Opus. A workspace is where your team does its work in Opus. Think of it like a shared folder for your team—everything inside (workflows, jobs, reviews) belongs to that team, and you control who can access it. ## What Can You Do With A Workspace? All your workflows, jobs, and reviews live in one place. Invite teammates and decide who can build, run, or review. See job history, results, and status all in one place. Route review tasks to the right people and track progress. ## What's Inside A Workspace? Every workspace contains: * **Workflows** — Your automation blueprints * **Jobs** — Runs of those workflows * **Reviews** — Items waiting for human approval * **Members** — Your team * **Settings** — Name, icon, and description ## Team Roles Everyone in a workspace has a role that determines what they can do: | Role | What They Can Do | | - | - | | **Admin** | Everything—build workflows, run jobs, manage the team, change settings | | **Builder** | Create and edit workflows, run jobs | | **Operator** | Run jobs and see results (can't edit workflows) | | **Reviewer** | Only see and complete review tasks assigned to them | ### What Each Role Can Do Admins have full control: * Create, edit, and delete workflows * Run jobs and see all results * Invite people and change their roles * Access all reviews Builders create and run workflows: * Create and edit workflows * Run jobs and see results * Complete reviews * Can't invite people or change settings Operators run workflows others have built: * See workflows (but not edit them) * Run jobs and see results * Complete reviews * Can't create workflows or manage the team Reviewers handle approval tasks: * See workflows related to their reviews * Complete review tasks assigned to them * Can't run jobs or edit anything ## Adding People To Your Workspace Click **Workspace Settings → Members** from your workspace. Click **Invite Members** and enter their email addresses. You can invite multiple people at once. Choose Admin, Builder, Operator, or Reviewer for each person. If you're adding Reviewers, choose which review queues they can see. Click send and track who's accepted in your members list. Inviting a whole team? Use bulk invitations—everyone gets the same role, and you can adjust individually later. ### Changing Someone's Access Admins can: * Change anyone's role * Update which reviews someone can see * Remove people from the workspace Every change is logged so you can see who did what. ## Customizing Your Workspace Make your workspace easy to find in **Workspace Settings → Profile**: | Setting | What It Does | | - | - | | **Name** | What your workspace is called | | **Icon** | A visual marker to spot it quickly | | **Description** | A short explanation of what this workspace is for | | **Tags** | Keywords to help people find it | Good names and descriptions help people find the right workspace fast—especially when your organization has lots of them. ## Ways To Organize Workspaces ### By Business Area * **Finance Workspace**: Invoicing, expense reports, financial automation * **Compliance Workspace**: KYC checks, regulatory workflows * **Operations Workspace**: Internal processes, HR automation * **QA Workspace**: Testing and quality checks ### By Team * Each team gets their own workspace * Team leads are Admins * Team members are Builders or Operators * Stakeholders are Reviewers ### By Stage * **Development Workspace**: For testing and building * **Production Workspace**: For live workflows with real data If you use sub-workflows (workflows that call other workflows), they all need to be in the same workspace. Keep this in mind when planning your setup. ## Tips For Running Your Workspace * Organize by team or business area—whatever makes sense for you * Remember that sub-workflows need to live together * Balance keeping things separate vs. making collaboration easy * **Admins**: Team leads, people who own the workflows * **Builders**: Developers, automation specialists * **Operators**: Business users who just need to run things * **Reviewers**: Approvers, QA, compliance folks ### Day-To-Day Tips 1. **Name things clearly** — Future you will thank you 2. **Check job history** — See what's working and what's failing 3. **Review access regularly** — Remove people who don't need it anymore ## How Workspaces Fit Into Organizations Workspaces live inside your organization and inherit some things automatically: * **Policies**: Review settings and workflow rules * **Features**: What's available based on your plan This setup lets your company set the rules while giving teams freedom to work their way. ``` Organization (company-wide settings and billing) └── Workspace A (Team Alpha) └── Workspace B (Team Beta) └── Workspace C (Shared automations) ``` ## Related Resources Company-wide settings that workspaces inherit. Build automations for your workspace. Run workflows and see results. The visual editor for creating workflows. # Introduction Source: https://developer.opus.com/index Design, execute, and govern AI-powered workflows at enterprise scale. ## What Is Opus? Opus is an AI-native enterprise workflow automation platform designed to orchestrate complex, document-heavy, back-office and compliance-critical operations. It combines large language models, deterministic logic, human-in-the-loop controls, and deep system integrations into a single, structured execution layer. Instead of requiring engineers to hard-code every process, Opus allows business and operations teams to describe processes in natural language or via a drag-and-drop Builder interface and converts these into auditable, reusable workflows that can be executed at scale. Describe processes in natural language and Opus generates executable workflows with tasks, branching logic, and typed inputs/outputs. Combine AI agents with human tasks, reviews, and decisions for supervised automation that maintains control and accountability. Full audit trails, immutable logs, and enterprise governance for regulated environments like KYC, claims, and financial reporting. Robust data contracts with validation, auto-linking of inputs/outputs, and predictable reuse across workflows. ## Core Concepts Opus organizes automation around two core primitives: **Workflows** and **Jobs**. | Concept | Description | | - | - | | **Workflows** | Design-time blueprints: graphs of tasks representing AI agents, human tasks, decisions, reviews, and integrations. Each workflow declares typed inputs and outputs, forming a strict contract. | | **Jobs** | Live runs of a workflow—each job captures inputs, executes the graph, and logs results for traceability. | | **Tasks** | Modular building blocks: Agent tasks for AI reasoning, Human tasks for tasks and reviews, Data tasks for connectivity, and Core tasks for workflow boundaries. | | **Workspaces** | Team-level spaces within an organization where groups build and run workflows independently with their own collaborators. | | **Organizations** | A company's Opus account encompassing all workspaces, users, billing, and platform-wide policies. | New to Opus? Start with the [Quickstart](/quickstart) to create your first workflow in minutes. ## Task Types Workflow logic is expressed through modular tasks that act as building blocks: Embed AI-powered reasoning and generation into workflows. * **Opus Agent**: Maximum capability agent that takes a natural language task description and intelligently figures out how to accomplish it. * **Custom Agent**: Simple one-shot LLM interaction from popular providers (OpenAI, Anthropic, DeepSeek, etc.) with explicit prompts and structured responses. * **Decision Agent**: Automated routing based on conditions defined via natural language or logical expressions. * **Opus Code**: Embed Python scripts for custom logic and transformations. Implement supervised automation, governance, and human tasks. * **Human Task**: Structured work items for people—collecting documentation, filling data fields, or making business judgment calls. * **Human Review**: A person reviews outputs and can accept, reject, or edit before the workflow proceeds. * **Human Decision Agent**: Same as Decision Agent, but a human evaluates the conditions and makes the routing decision. AI-powered quality assurance at scale. * **Agentic Review**: AI agents autonomously check previous AI outputs against defined criteria—key for workflows requiring mission-critical accuracy. Handle connectivity and data movement. * **Import/Export Data**: Ingest from and push to documents, applications, storage, or databases. * **Text Extraction (OCR)**: Transform images and documents into machine-readable text. * **External Service**: Connect to any external REST API, with or without authentication. Call another workflow as a sub-workflow with automated input/output mapping. Build libraries of reusable sub-processes (KYC checks, claims validation, document extraction) that compose into larger enterprise workflows. ## How It Works Use the Builder to design workflows visually, or describe your process in natural language and let prompt-to-workflow generation create an initial draft. Opus AI Assist helps you add, remove, or reconfigure tasks using natural language. Define typed inputs and outputs at the workflow level. Configure agent prompts, human task forms, review criteria, and integrations. Mark inputs as required or optional with validation rules. Run previews directly in the Builder to validate logic. See real-time state feedback, debug issues, and iterate before activation. Activate your workflow and run it as Jobs—manually or via API. Every job produces an immutable audit trail: input payloads, intermediate results, review decisions, and final outputs. ## Built For Regulated Environments Opus is explicitly designed for high-stakes, compliance-critical operations. Every job produces a detailed audit trail supporting use cases like: * **KYC/AML workflows** — Identity verification, document validation, risk scoring * **Claims adjudication** — Evidence review, policy matching, approval routing * **Clinical documentation** — Medical record processing, compliance checks * **Financial reporting** — Data extraction, validation, regulatory submissions Opus is focused on **enterprise workflow automation** for back-office, document-centric knowledge work. It is not a chatbot platform, voice agent, or media generation system—its core competency is orchestrating AI, people, decisions, and systems around documents, data, and business rules. ## Get Started Create and run your first workflow in under 5 minutes. Learn how to use the visual workflow editor and AI Assist. Understand workflow structure, lifecycle, and best practices. Execute workflows and monitor job status and results. ## Governance And Access Configure organization-level settings, policies, and integrations. Manage team collaboration, roles, and resource boundaries. ## API And Integrations Programmatically trigger jobs, upload files, and retrieve results. Connect to external services like Google Sheets, Slack, AWS S3, and more. # Integrations Marketplace Source: https://developer.opus.com/integrations/overview Connect Opus workflows with 3,500+ external services and 36,000+ actions. Opus's Integration Marketplace provides pre-built connectors to thousands of external services, enabling your workflows to interact with the tools your organization already uses. ## Key Capabilities Connect to cloud storage, productivity tools, databases, communication platforms, and more. Access a comprehensive library of pre-built actions for each integration. Secure credential storage with organization, workspace, and individual scoping. Connect services through OAuth or API keys without writing code. ## Using Integrations ### In Workflows Once you've configured integrations here in the marketplace, use them in your workflows through the Integrations Task: Add pre-configured integrations to your workflow to import data, export results, send notifications, and more. ## Setting Up Integrations Go to the **Integrations Marketplace** from the left navigation bar in the Opus platform. Browse or search for the service you want to connect—Google Sheets, Slack, AWS S3, Salesforce, and thousands more. Choose your authentication method and connect your account. Opus supports: * **OAuth**: Sign in with your service account * **API Key**: Paste your API key * **Access Token**: Provide your access token * **JWT**: Use JSON Web Token authentication * **Custom Auth**: Configure custom authentication headers * **No Auth**: For services that don't require authentication * And many more depending on the service. Configure your credential by providing: * **Action**: Select what this credential will be used for * **Name**: Give your credential a recognizable name * **Description**: Add a description to help identify this credential later Currently, Opus only supports **organization-scoped credentials**, which means any credentials you create can be used by all users in your organization. Support for workspace and personally-scoped credentials is coming soon. Add an [Integrations Task](/tasks/data/integrations) in the Builder and select your pre-configured integration. ## Best Practices * OAuth tokens may expire and require re-authentication * Test integrations regularly to catch issues early * Verify credentials work before activating workflows * Test with representative data * Confirm read/write permissions are correct * Grant only the permissions needed for your workflow * Use read-only credentials when writes aren't required * Scope to specific folders or resources when possible ## Custom APIs For APIs not covered by the Integration Marketplace, use the External Service task: Connect to any REST API with custom authentication and request configuration. ## Related Resources Use pre-configured integrations in your workflows. Connect to custom APIs not in the marketplace. Manage organization-level integrations. Configure workspace-scoped integrations. # Opus Docs MCP Server Source: https://developer.opus.com/mcp-setup Connect Opus documentation to AI-powered development tools using the Model Context Protocol. Opus exposes an MCP (Model Context Protocol) server that lets AI-powered development tools search and retrieve content from these docs directly. This means your IDE or AI assistant can pull in relevant Opus documentation as context while you work. The server is hosted at: ``` https://developer.opus.com/mcp ``` ## Connect Your Tools Run the following command in your terminal: ```bash theme={null} claude mcp add --transport http Opus https://developer.opus.com/mcp ``` Restart Claude Code for the server to become available. You can verify the connection with: ```bash theme={null} claude mcp list ``` Add the following to `~/.cursor/mcp.json`: ```json theme={null} { "mcpServers": { "Opus": { "url": "https://developer.opus.com/mcp", "type": "http" } } } ``` Restart Cursor to pick up the new server. Add the following to `.vscode/mcp.json` in your project root: ```json theme={null} { "servers": { "Opus": { "type": "http", "url": "https://developer.opus.com/mcp" } } } ``` ## What It Does Once connected, your AI tool gets access to a search function over the full Opus documentation. This includes guides, API references, task documentation, and integration pages. You can ask questions like: * "How do I execute a job via the Opus API?" * "What task types does Opus support?" * "How do I set up a workflow with human review?" The tool will pull in the relevant documentation pages to provide grounded, accurate answers. ## Rate Limits | Scope | Limit | | - | - | | Per user (IP) | 200 requests/hour | The MCP server is read-only. It provides search access to public documentation and does not interact with the Opus platform API or your workflows. # Available Packages Source: https://developer.opus.com/opus-sdk/available-packages Python standard-library and third-party packages available inside Opus Code. An Opus Code task runs your Python in a secure environment that ships with a curated set of packages. You can `import` any of the packages below directly in your code—alongside the [Opus SDK](/opus-sdk/overview)—without installing anything. The Opus SDK itself (the `Opus` object) is always available inside Opus Code without an import. See the [Opus SDK overview](/opus-sdk/overview) for what it exposes. ## Standard Library These modules ship with Python and are available in every Opus Code task. | Category | Packages | | - | - | | **Data** | `json`, `csv`, `collections`, `dataclasses`, `enum`, `copy` | | **Text** | `re`, `string`, `html` | | **Math** | `math`, `statistics`, `random`, `decimal`, `fractions` | | **Time** | `datetime`, `time` | | **Utilities** | `itertools`, `functools`, `typing`, `uuid` | | **Encoding** | `hashlib`, `base64` | | **Markup & Archives** | `xml`, `zipfile` | | **Advanced** | `abc`, `warnings`, `contextlib`, `concurrent`, `concurrent.futures` | ## Third-Party Packages These packages are pre-installed and ready to import. Where the import name differs from the package name, both are shown. | Category | Packages | | - | - | | **HTTP** | `requests` | | **Office Documents** | `openpyxl`, `docx` (python-docx), `pptx` (python-pptx) | | **PDF** | `PyPDF2`, `pdfplumber`, `fitz` (pymupdf), `reportlab`, `fpdf` (fpdf2), `pdf2docx`, `pdf2image` | | **Images** | `PIL` (pillow), `cv2` (opencv-python-headless) | | **Utilities** | `magic` (python-magic), `dateutil` (python-dateutil), `toon_format` (toon-format) | For packages with an import alias, use the import name on the left in your code—for example `import fitz` for pymupdf, or `import cv2` for opencv-python-headless. See [File Formats](/opus-sdk/file-formats) for which formats the SDK reads and writes directly. ## Related Learn what the always-available `Opus` object exposes. See which file formats the SDK can read and write. Write custom Python logic inside a workflow. # Working with File Formats Source: https://developer.opus.com/opus-sdk/file-formats Recipes for reading and writing CSV, XML, XLSX, PDF, DOCX, and PPTX files with the Opus SDK. These recipes build on the core file API described in [Overview](/opus-sdk/overview) and use the libraries listed in [Available Packages](/opus-sdk/available-packages). Each example runs in an [Opus Code](/tasks/agent/opus-code) task, where `Opus.file.create`, `Opus.file.download`, and `Opus.file.upload` give you everything you need to read, transform, and produce files. ## CSV Files **Create a simple CSV from scratch:** ```python theme={null} import csv output = Opus.file.create("results", "CSV") with output.open("w") as f: writer = csv.writer(f) writer.writerow(["name", "score"]) writer.writerow(["Alice", 95]) writer.writerow(["Bob", 87]) file_url = Opus.file.upload(output) ``` **Build a CSV with DictWriter:** ```python theme={null} import csv output = Opus.file.create("inventory", "CSV") with output.open("w") as f: writer = csv.DictWriter(f, fieldnames=["product", "quantity", "price"]) writer.writeheader() writer.writerow({"product": "Widget", "quantity": 100, "price": 25.00}) writer.writerow({"product": "Gadget", "quantity": 50, "price": 49.99}) file_url = Opus.file.upload(output) ``` **Read and filter a downloaded CSV:** ```python theme={null} import csv file = Opus.file.download("https://files.opus.com/data/employees.csv") with file.open("r") as f: reader = csv.DictReader(f) for row in reader: if int(row["score"]) > 30: print(row["name"], row["score"]) ``` **Download a CSV, filter rows, and upload as a new file:** ```python theme={null} import csv source = Opus.file.download("https://files.opus.com/data/scores.csv") output = Opus.file.create("high_scores", "CSV") with source.open("r") as src, output.open("w") as dst: reader = csv.DictReader(src) writer = csv.DictWriter(dst, fieldnames=reader.fieldnames) writer.writeheader() for row in reader: if float(row["score"]) > 90: writer.writerow(row) file_url = Opus.file.upload(output) ``` ## XML Files **Create an XML file from scratch:** ```python theme={null} import xml.etree.ElementTree as ET root = ET.Element("catalog") for title, price in [("Widget", "25.00"), ("Gadget", "49.99")]: item = ET.SubElement(root, "item") ET.SubElement(item, "title").text = title ET.SubElement(item, "price").text = price output = Opus.file.create("catalog", "XML") tree = ET.ElementTree(root) ET.indent(tree) with output.open("wb") as f: tree.write(f, encoding="utf-8", xml_declaration=True) file_url = Opus.file.upload(output) ``` **Parse a downloaded XML file:** ```python theme={null} import xml.etree.ElementTree as ET file = Opus.file.download("https://files.opus.com/data/catalog.xml") tree = ET.parse(file.open("r")) root = tree.getroot() for item in root.findall("item"): title = item.find("title").text price = item.find("price").text print(f"{title}: ${price}") ``` **Download an XML, modify it, and re-upload:** ```python theme={null} import xml.etree.ElementTree as ET file = Opus.file.download("https://files.opus.com/data/config.xml") tree = ET.parse(file.open("r")) root = tree.getroot() # Update a setting setting = root.find(".//setting[@name='timeout']") if setting is not None: setting.set("value", "60") ET.indent(tree) with file.open("wb") as f: tree.write(f, encoding="utf-8", xml_declaration=True) new_url = Opus.file.upload(file) ``` ## XLS & XLSX Files Use `openpyxl` to read and write XLSX spreadsheets. **Create an XLSX from scratch:** ```python theme={null} from openpyxl import Workbook wb = Workbook() ws = wb.active ws.title = "Sales" ws.append(["product", "quantity", "price"]) ws.append(["Widget", 100, 25.00]) ws.append(["Gadget", 50, 49.99]) output = Opus.file.create("sales_report", "XLSX") with output.open("wb") as f: wb.save(f) file_url = Opus.file.upload(output) ``` **Read and filter a downloaded XLSX:** ```python theme={null} from openpyxl import load_workbook file = Opus.file.download("https://files.opus.com/data/report.xlsx") wb = load_workbook(file.open("rb")) ws = wb.active headers = [cell.value for cell in ws[1]] for row in ws.iter_rows(min_row=2, values_only=True): data = dict(zip(headers, row)) if data["quantity"] > 50: print(data["product"], data["quantity"]) ``` **Download an XLSX, modify it, and re-upload:** ```python theme={null} from openpyxl import load_workbook file = Opus.file.download("https://files.opus.com/data/report.xlsx") wb = load_workbook(file.open("rb")) ws = wb.active # Add a total row total = sum(row[2] for row in ws.iter_rows(min_row=2, values_only=True)) ws.append(["Total", "", total]) with file.open("wb") as f: wb.save(f) new_url = Opus.file.upload(file) ``` **Convert a downloaded XLSX to CSV:** ```python theme={null} import csv from openpyxl import load_workbook file = Opus.file.download("https://files.opus.com/data/report.xlsx") wb = load_workbook(file.open("rb")) ws = wb.active output = Opus.file.create("report", "CSV") with output.open("w") as f: writer = csv.writer(f) for row in ws.iter_rows(values_only=True): writer.writerow(row) file_url = Opus.file.upload(output) ``` ## PDF Files Three PDF libraries are available: `fitz` (PyMuPDF), `fpdf2`, and `PyPDF2`. ### PyMuPDF (`fitz`) **Create a PDF from scratch:** ```python theme={null} import fitz doc = fitz.open() page = doc.new_page() page.insert_text(fitz.Point(72, 72), "Hello, world!", fontsize=16) page.insert_text(fitz.Point(72, 100), "Generated with PyMuPDF.", fontsize=12) output = Opus.file.create("greeting", "PDF") doc.save(output.open("wb")) doc.close() file_url = Opus.file.upload(output) ``` **Extract text from a downloaded PDF:** ```python theme={null} import fitz file = Opus.file.download("https://files.opus.com/data/document.pdf") doc = fitz.open(file.open("rb")) for page in doc: print(page.get_text()) doc.close() ``` **Extract text from a specific page range:** ```python theme={null} import fitz file = Opus.file.download("https://files.opus.com/data/document.pdf") doc = fitz.open(file.open("rb")) for page in doc[2:5]: # pages 3 through 5 (0-indexed) print(f"--- Page {page.number + 1} ---") print(page.get_text()) doc.close() ``` **Download a PDF, add a watermark, and re-upload:** ```python theme={null} import fitz file = Opus.file.download("https://files.opus.com/data/report.pdf") doc = fitz.open(file.open("rb")) for page in doc: page.insert_text( fitz.Point(200, 400), "CONFIDENTIAL", fontsize=48, color=(0.8, 0, 0), rotate=270, ) doc.save(file.open("wb")) doc.close() new_url = Opus.file.upload(file) ``` **Extract images from a PDF and upload each as PNG:** ```python theme={null} import fitz file = Opus.file.download("https://files.opus.com/data/report.pdf") png_file_urls = [] doc = fitz.open(file.open("rb")) for page_num, page in enumerate(doc): for img_index, img in enumerate(page.get_images()): xref = img[0] pix = fitz.Pixmap(doc, xref) output = Opus.file.create(f"page{page_num + 1}_img{img_index + 1}", "PNG") output.write_bytes(pix.tobytes("png")) file_url = Opus.file.upload(output) png_file_urls.append(file_url) pix = None doc.close() ``` **Convert each page of a PDF to a PNG image:** ```python theme={null} import fitz file = Opus.file.download("https://files.opus.com/data/document.pdf") png_file_urls = [] doc = fitz.open(file.open("rb")) for page in doc: pix = page.get_pixmap(dpi=150) output = Opus.file.create(f"page_{page.number + 1}", "PNG") output.write_bytes(pix.tobytes("png")) file_url = Opus.file.upload(output) png_file_urls.append(file_url) pix = None doc.close() ``` ### PyPDF2 **Merge multiple downloaded PDFs into one:** ```python theme={null} from PyPDF2 import PdfMerger urls = [ "https://files.opus.com/data/part1.pdf", "https://files.opus.com/data/part2.pdf", "https://files.opus.com/data/part3.pdf", ] merger = PdfMerger() for url in urls: file = Opus.file.download(url) merger.append(file.open("rb")) output = Opus.file.create("merged", "PDF") merger.write(output.open("wb")) merger.close() file_url = Opus.file.upload(output) ``` **Extract specific pages from a PDF:** ```python theme={null} from PyPDF2 import PdfReader, PdfWriter file = Opus.file.download("https://files.opus.com/data/document.pdf") reader = PdfReader(file.open("rb")) writer = PdfWriter() for page_num in [0, 2, 4]: # pages 1, 3, 5 (0-indexed) writer.add_page(reader.pages[page_num]) output = Opus.file.create("selected_pages", "PDF") writer.write(output.open("wb")) file_url = Opus.file.upload(output) ``` **Rotate pages in a PDF:** ```python theme={null} from PyPDF2 import PdfReader, PdfWriter file = Opus.file.download("https://files.opus.com/data/document.pdf") reader = PdfReader(file.open("rb")) writer = PdfWriter() for page in reader.pages: page.rotate(90) writer.add_page(page) with file.open("wb") as f: writer.write(f) new_url = Opus.file.upload(file) ``` ## DOCX Files Use `python-docx` to read and write Word documents. **Create a DOCX from scratch:** ```python theme={null} from docx import Document doc = Document() doc.add_heading("Monthly Report", level=1) doc.add_paragraph("This report covers Q1 performance.") table = doc.add_table(rows=1, cols=3) table.style = "Table Grid" table.rows[0].cells[0].text = "Product" table.rows[0].cells[1].text = "Quantity" table.rows[0].cells[2].text = "Price" for product, qty, price in [("Widget", "100", "$25.00"), ("Gadget", "50", "$49.99")]: row = table.add_row() row.cells[0].text = product row.cells[1].text = qty row.cells[2].text = price output = Opus.file.create("monthly_report", "DOCX") doc.save(output.open("wb")) file_url = Opus.file.upload(output) ``` **Read text from a downloaded DOCX:** ```python theme={null} from docx import Document file = Opus.file.download("https://files.opus.com/data/report.docx") doc = Document(file.open("rb")) for para in doc.paragraphs: print(para.text) ``` **Read tables from a downloaded DOCX:** ```python theme={null} from docx import Document file = Opus.file.download("https://files.opus.com/data/report.docx") doc = Document(file.open("rb")) for table in doc.tables: for row in table.rows: print([cell.text for cell in row.cells]) ``` **Download a DOCX, modify it, and re-upload:** ```python theme={null} from docx import Document file = Opus.file.download("https://files.opus.com/data/report.docx") doc = Document(file.open("rb")) doc.add_heading("Appendix", level=2) doc.add_paragraph("Additional notes added programmatically.") doc.save(file.open("wb")) new_url = Opus.file.upload(file) ``` ## PPTX Files Use `python-pptx` to read and modify PowerPoint presentations. PPTX is not a supported file type for `Opus.file.create`. You can download existing PPTX files, modify them, and re-upload. **Read text from all slides of a downloaded PPTX:** ```python theme={null} from pptx import Presentation file = Opus.file.download("https://files.opus.com/data/presentation.pptx") prs = Presentation(file.open("rb")) for slide_num, slide in enumerate(prs.slides, 1): print(f"--- Slide {slide_num} ---") for shape in slide.shapes: if shape.has_text_frame: print(shape.text) ``` **Download a PPTX, add a slide, and re-upload:** ```python theme={null} from pptx import Presentation from pptx.util import Inches, Pt file = Opus.file.download("https://files.opus.com/data/presentation.pptx") prs = Presentation(file.open("rb")) slide_layout = prs.slide_layouts[1] # title + content layout slide = prs.slides.add_slide(slide_layout) slide.shapes.title.text = "Summary" slide.placeholders[1].text = "Automatically generated slide." prs.save(file.open("wb")) new_url = Opus.file.upload(file) ``` **Download a PPTX and replace text across all slides:** ```python theme={null} from pptx import Presentation file = Opus.file.download("https://files.opus.com/data/template.pptx") prs = Presentation(file.open("rb")) for slide in prs.slides: for shape in slide.shapes: if shape.has_text_frame: for paragraph in shape.text_frame.paragraphs: for run in paragraph.runs: run.text = run.text.replace("{{COMPANY}}", "Acme Corp") prs.save(file.open("wb")) new_url = Opus.file.upload(file) ``` ## Related Learn the core file API: create, download, and upload. See every Python library you can import in Opus Code. Run these recipes in a Python task inside your workflow. # Opus SDK Source: https://developer.opus.com/opus-sdk/overview Work with files in Opus storage from inside an Opus Code task — download, create, and upload files with the Opus SDK. The Opus SDK lets you work with files from inside an [Opus Code](/tasks/agent/opus-code) task—download files from Opus storage, create new files, upload files back to storage, and more. Aside from the Opus SDK, you can use a wide range of Python packages; the full list is available in [Available Packages](/opus-sdk/available-packages). ## Setup Inside an Opus Code task, `Opus` is already defined and ready to use. ## File Operations All file operations are accessed via `Opus.file`. ### Downloading a File Use `Opus.file.download(file_url)` to fetch a file from Opus storage by its URL: ```python theme={null} file = Opus.file.download("https://files.opus.com/path/to/file.pdf") ``` This returns an [OpusFile](#opusfile-interface) object. Modifications to downloaded files are local only unless uploaded via `Opus.file.upload`, which creates a new file and returns a new URL; the original remote file is never modified. ### Getting a Presigned Download URL Use `Opus.file.presigned_download(file_url, expiry=None)` to get a presigned URL for downloading a file without fetching it locally: ```python theme={null} url = Opus.file.presigned_download("https://files.opus.com/path/to/file.pdf") ``` You can optionally set a custom expiry (in seconds, between 60 and 86400): ```python theme={null} url = Opus.file.presigned_download("https://files.opus.com/path/to/file.pdf", expiry=3600) # 1 hour ``` If no `expiry` is provided, the server default is used. The `expiry` must be between 60 seconds (1 minute) and 86400 seconds (24 hours). Values outside this range raise `InvalidFileExpiryError`. ### Creating a File Use `Opus.file.create(file_name, file_type)` to create a new empty file: ```python theme={null} new_file = Opus.file.create("my_report", "PDF") ``` The first argument is the file name (without extension), the second is the file type. The extension is added automatically based on the type. This returns an [OpusFile](#opusfile-interface) object. If the file isn't uploaded via `Opus.file.upload`, the created file won't be persisted. Creating a file with a name that already exists in the current session raises `FileAlreadyExistsError`. #### Supported File Types Pass any of these as the `file_type` argument: | Type | Extension | Content Type | | - | - | - | | `JPEG` | `.jpeg` | `image/jpeg` | | `PNG` | `.png` | `image/png` | | `JPG` | `.jpg` | `image/jpg` | | `CSV` | `.csv` | `text/csv` | | `PDF` | `.pdf` | `application/pdf` | | `DOCX` | `.docx` | `application/vnd.openxmlformats...` | | `PPTX` | `.pptx` | `application/vnd.openxmlformats...` | | `XLS` | `.xls` | `application/vnd.ms-excel` | | `XLSX` | `.xlsx` | `application/vnd.openxmlformats...` | | `TXT` | `.txt` | `text/plain` | | `MD` | `.md` | `text/markdown` | | `JSON` | `.json` | `application/json` | | `HTML` | `.html` | `text/html` | | `XML` | `.xml` | `application/xml` | The type is case-insensitive: `"pdf"`, `"PDF"`, and `"Pdf"` all work. ### Uploading a File Use `Opus.file.upload(file, access_scope="all")` to upload an [OpusFile](#opusfile-interface) to Opus storage. ```python theme={null} file_url = Opus.file.upload(new_file) print(file_url) # "https://files.opus.com/..." ``` The `access_scope` parameter is optional and defaults to `"all"`. **Code Playground:** In the code playground, the `access_scope` is always `"unlisted"` regardless of the value provided. You can upload the same file multiple times. Each upload returns a new URL. #### Supported Access Scopes | Scope | Description | | - | - | | `all` | Visible to everyone (default) | | `workspace` | Visible only to current workspace members | | `unlisted` | Not listed — accessible only via direct file URL | The scope is case-insensitive: `"Workspace"`, `"WORKSPACE"`, and `"WorkSpace"` all work. ```python theme={null} file_url = Opus.file.upload(new_file, access_scope="workspace") ``` ### OpusFile Interface `OpusFile` is the object returned by `download()` and `create()`. Its attributes are read-only. #### Properties | Property | Type | Description | | - | - | - | | `file_name` | `str \| None` | File name without extension. | | `file_ext` | `str` | Extension including leading dot (e.g. `".pdf"`). | | `file_type` | `str` | Resolved file type enum value. Check [Supported File Types](#supported-file-types). | | `file_size` | `int` | Current size on disk in bytes. | ```python theme={null} file = Opus.file.create("report", "PDF") print(file.file_name) # "report" print(file.file_ext) # ".pdf" print(file.file_type) # FileType.PDF print(file.file_size) # 0 (empty file) ``` #### Operations | Method | Description | | - | - | | `read_bytes() -> bytes` | Read entire file content as bytes. | | `read_text(encoding="utf-8") -> str` | Read entire file content as a string. | | `write_bytes(data: bytes)` | Replace file content with binary data. | | `write_text(data: str, encoding="utf-8")` | Replace file content with text. | | `open(mode="rb")` | Open the underlying file and return a file handle. | #### Examples **Reading:** ```python theme={null} # As text text = file.read_text() # As bytes data = file.read_bytes() # Using a file handle with file.open("r") as f: for line in f: print(line) ``` **Writing:** ```python theme={null} # Replace all content file.write_text("Hello, world!") file.write_bytes(b"\x50\x4b\x03\x04...") # Streaming writes with file.open("w") as f: f.write("line 1\n") f.write("line 2\n") # Appending with file.open("a") as f: f.write("appended line\n") ``` **Download, modify, and re-upload:** ```python theme={null} file = Opus.file.download("https://files.opus.com/reports/data.csv") original = file.read_text() modified = original.replace("old_value", "new_value") file.write_text(modified) new_url = Opus.file.upload(file) ``` **Create a CSV from scratch:** ```python theme={null} import csv output = Opus.file.create("results", "CSV") with output.open("w") as f: writer = csv.writer(f) writer.writerow(["name", "score"]) writer.writerow(["Alice", 95]) writer.writerow(["Bob", 87]) file_url = Opus.file.upload(output) ``` **Create a JSON file:** ```python theme={null} import json output = Opus.file.create("config", "JSON") output.write_text(json.dumps({"key": "value", "count": 42}, indent=2)) file_url = Opus.file.upload(output) ``` **Process a downloaded file line by line:** ```python theme={null} file = Opus.file.download("https://files.opus.com/logs/app.txt") with file.open("r") as f: for line in f: if "ERROR" in line: print(line.strip()) ``` ### Working with File Formats For format-specific helpers and patterns, check the dedicated guide: [Working with File Formats](/opus-sdk/file-formats). ## Errors All SDK exceptions inherit from `OpusError` and are available via `Opus.errors`: ```python theme={null} try: file = Opus.file.download("https://files.opus.com/missing.pdf") except Opus.errors.FileAPIError as e: print(f"Download failed: {e}") print(f"Status code: {e.status_code}") print(f"Response: {e.response_body}") ``` ```python theme={null} try: Opus.file.create("report", "MP4") except Opus.errors.UnsupportedFileTypeError as e: print(f"Bad type: {e}") ``` ```python theme={null} try: Opus.file.create("report", "PDF") Opus.file.create("report", "PDF") # same name again except Opus.errors.FileAlreadyExistsError as e: print(f"Duplicate: {e}") ``` | Exception | When it's raised | | - | - | | `OpusError` | Base class for all SDK errors. Also raised directly for generic failures. | | `FileAPIError` | An API call failed (download or upload). | | `FileAlreadyExistsError` | `create()` with a name that already exists. | | `UnsupportedFileTypeError` | `create()` with an unrecognized file type. | | `InvalidFileExpiryError` | `presigned_download()` with an expiry outside the range. | | `UnsupportedAccessScopeError` | `upload()` with an invalid access scope. | | `PathTraversalError` | File name attempted to escape the allowed directory. | ## Related Browse the full list of Python packages you can import in Opus Code. Format-specific helpers for reading and writing PDFs, spreadsheets, and more. Write custom Python code directly in your workflow. # Opus Quickstart Source: https://developer.opus.com/quickstart Create and execute your first Opus workflow in under 5 minutes. This guide walks you through creating a simple workflow, testing it with a preview, and running it as a job. By the end, you'll understand the core Opus workflow: design, preview, activate, and execute. ## Prerequisites Before you begin, ensure you have: * An Opus account (all users get a personal organization and workspace by default) * Builder or Admin role in your workspace Don't have an account yet? Contact your organization admin or [request access](mailto:support@opus.com). ## Create Your First Workflow From the **Workflows** page, click **New Workflow**. This opens the create workflow page where you can choose to use prompt-to-workflow, start from a template, or build from scratch. For this guide, select **Build from scratch** to open the visual workflow editor with an empty Builder. The Builder loads with **Workflow Input** and **Workflow Output** tasks by default. Click on the Workflow Input task to open its configuration panel, then click the **+** button to create a new input variable: * **Display name**: `document_text` * **Type**: Text * **Description**: "The text content to process" Opus supports a **Generate Variable** feature that creates mock data for your input variables. Click the **Generate Variable** button in the Workflow Input task to have Opus auto-generate sample values, allowing you to quickly test workflows without manually entering data. Click the **+** button in the Builder and add an **Opus Agent** task. Draw an edge from the **Workflow Input** task to the **Opus Agent** task to establish the data flow. Once the edge is drawn, the input for the Opus Agent task is automatically set to `document_text` from the previous step. Edges define both data dependencies and execution order. A task only runs when all upstream dependencies have completed successfully. The Opus Agent configuration panel is divided into three sections: * **Input configuration**: Variables the agent receives (already linked from your connection) * **Output**: Variables the agent produces * **Prompt box**: At the bottom, a text field labeled "Describe what you want to change" To configure the agent, enter your task description in the prompt box at the bottom: ``` Summarize the following text in 3 bullet points ``` After entering your task description, you must click the **Generate Blueprint** button (the black box with an arrow icon) to generate the blueprint. This allows the Opus Agent to determine its objective, task description, and the required steps to complete the task. Once the blueprint is generated, the Opus Agent is ready to run. The agent will automatically create output variables based on your task description. For this quickstart, we'll use the output variables created by the Opus Agent rather than specifying our own. You can also manually specify your own output variables in the Output section before generating the blueprint. When generating the blueprint, Opus Agent may also create its own input variables. If this happens, you need to link these input variables to the workflow input variables you created earlier. To do this: 1. Click the **edit icon** next to the created variable 2. In the configuration panel, link it to your workflow input variables Opus supports an intelligent **auto-link** feature that automatically connects variables between tasks. Click the auto-link button to have Opus intelligently map matching inputs and outputs for you. Draw an edge from the **Opus Agent** task to the **Workflow Output** task. Click on the Workflow Output task to open its configuration panel. You can create output variables for your workflow by clicking the **+** button, then link them to the output variables from your Opus Agent. Use the auto-link feature or manually select the Opus Agent outputs in the variable configuration panel. Click the **Tidy Up** button in the Builder toolbar to automatically format and arrange your workflow tasks in a clean, organized layout. This is especially helpful as workflows grow more complex. ## Run Your Workflow Before activating, test your workflow in the Builder. The **Action Center** is located at the top center of the Builder. It displays all pending action items that must be resolved before you can run your workflow. * Review any issues listed (missing connections, unconfigured variables, etc.) * Use the **Auto-fix** button to let Opus AI automatically resolve issues * Once the Action Center shows "No action items," your workflow is ready to test The Action Center's Auto-fix feature can save time by intelligently resolving common configuration issues using Opus AI. Click the **Run Workflow** button in the toolbar. Watch as: * Tasks animate to show execution progress * State indicators show scheduled, running, completed, or failed status * Results appear on each task as they complete A success banner appears when your workflow completes without errors. Click on the Workflow Output task to see your summarized text. If something looks wrong, edit your tasks and run the workflow again. **Caching for cost savings**: The Builder caches data from completed runs. When you run the workflow again, tasks with unchanged inputs will use cached results instead of re-executing. To perform a completely fresh run where all data is recalculated, click the **Clear Saved Data** button (located to the right of the Run Workflow button) before running. ## Activate Your Workflow Once your workflow runs successfully in the Builder, click the **Activate** button to make it available for production use. This changes the workflow status from **Draft** to **Active**. Only active workflows can be executed as jobs. Draft workflows are for design and testing only. ## Execute A Job Jobs are production runs of your workflow with real inputs and auditable outputs. Click **New Job** from your workflow details page (your workflow will be pre-selected), or go to **Jobs** in the sidebar and click **New Job** to choose from all available workflows. Select your "Text Summarizer" workflow (or whatever you named it). Enter the text you want to summarize. Click **Execute Job**. The platform: * Validates inputs against the workflow schema * Queues the job for execution * Runs each task in dependency order * Records outputs and logs for audit Credit usage is estimated before execution and deducted only upon successful completion. Track job status in the Jobs dashboard. Once completed: * View outputs directly in the UI * Access full audit logs for compliance ## What You've Learned You've completed the core Opus workflow: | Step | What you did | | - | - | | **Design** | Created a workflow with input, AI processing, and output tasks | | **Test** | Ran the workflow in the Builder with sample data before activation | | **Activate** | Changed status from Draft to Active for production use | | **Execute** | Ran a job with real inputs and retrieved auditable results | ## Next Steps Learn about all available tasks, integrations, and advanced Builder features. Understand workflow lifecycle, sub-workflows, and optimization patterns. Connect to Google Sheets, Slack, AWS S3, and more. Trigger jobs programmatically and integrate with your existing systems. # v0.86 Beta (Oct 3, 2025) Source: https://developer.opus.com/release-notes/opus-v0-86-beta Released Oct 3, 2025. Major Agentic review supercharged, new models, wider credentials reach, organization names no longer need to be platform unique. ### Builder * **Custom Agent:** New models supported (GPT-5, GPT-5 nano, GPT-5 mini, Claude Sonnet 4.5). * **Custom Agent:** Existing models deprecated (AWS Nova Lite, AWS Nova Pro, Mistral Large 2, Pixtral Large). * **Human Review and Human Task:** Ability to set deadline from within the task definition (1hr to 24hrs). * **External Service: Preview full Header & Request Body:** various visual improvements and coverage of edge cases. * **Task Variable Flow Links:** 20+ bugs fixed relating to linking variables, unlinking behaviour on task and edge deletion, auto-linking, previewing variables of different types on Workflow Output, edge cases on Workflow Output. ### Platform * **Free Manhours:** 25 Manhours added to all new accounts for EAuth and OAuth signups. Referral codes add Manhours on top of this 25 new baseline. * **Credentials scoped by Organization:** Credentials are now accessible across workflows and workspaces in the same organization. However, not across organizations. * **Tasks with File Variables:** File based prompts context window now \~1M tokens (note this includes text and any system prompts). * **Usability:** Platform tooltips and onboarding tutorial on the platform side expanded. * **Workflow Sharing:** Improved design for sharing Workflows. * **Workflow Listing:** Fixed visual bug on text overflowing when Workspace name is too long. * **Agentic Review:** Removed "Variable to Review" parameter, all variables are reviewed as part of the agentic pattern. * **Organization Name:** No longer need to be unique across the platform. # v0.87 Beta (Oct 7, 2025) Source: https://developer.opus.com/release-notes/opus-v0-87-beta Released Oct 7, 2025. Major Human-reviewable AI decision workflows introduced with Human Decision Agent, enhanced type validation, and new Job management features. ### Builder * **Human Decision Agent:** Adds support for human-reviewable decision flows that can evaluate logical expressions and LLM-based decision contexts. * **Opus Agent:** Removed legacy task blueprint remnants that persisted even after users manually revised Agent task definitions. * **Context Aware Type Validation:** Implements improved variable typing with stronger safeguards for non-technical users. ### Jobs * **Filters:** Enhanced capability to filter Jobs by multiple status values simultaneously. * **Input:** Redesigned UI for manual Job variable creation, with specific enhancements for objects, lists, and file handling. * **Validation:** Strengthened type checking and file validation prior to Job execution. * **Output:** Added direct download functionality for Job output files. * **Duplicate Job:** New feature enables Job duplication. * **Delete Job:** New feature enables Job deletion. ### Platform * **Workflow Generation:** Implemented click throttling to prevent duplicate generation requests for identical prompts. * **Onboarding:** Onboarding cards now support dismissal via keyboard shortcuts and clicking outside the card area. * **Referral & Partner Codes:** Codes can now be applied retroactively through Organization Settings → Referrals & Partners, supporting promotional campaigns. # v0.88 Beta (Oct 9, 2025) Source: https://developer.opus.com/release-notes/opus-v0-88-beta Released Oct 9, 2025. Minor New feasibility guardrails ensure that the objectives of Opus Agents are realistic and achievable with available tools. ### Builder * **Task Placement:** Mouse position now guides task placement during Workflow design for improved efficiency. * **Feasibility Guardrail:** Opus Agent validates that objectives can be accomplished using LLM networks; rejects tasks requiring integrations. * **Human Decision Agent:** Added feature supporting human decision deadlines ranging from 1 to 24 hours. * **Menu Navigation:** Enhanced scroll bar visibility across additional devices. * **Toast Messages:** Improved in-app notifications and messages for better usability and error communication. ### Workflow Generation * **Button Timing:** Resolved issue where "Go to Workflow" button appeared before generated Workflows were fully prepared. * **Missing Edges:** Fixed rare bug where certain variables required in Workflows weren't included in Workflow Input. ### Platform * **Workflow Templates:** Streamlined and condensed card layouts to accelerate template searches. * **Jobs:** Various layout refinements for different variable types. # v0.89 Beta (Oct 14, 2025) Source: https://developer.opus.com/release-notes/opus-v0-89-beta Released Oct 14, 2025. Minor Enhanced capabilities for external service integrations with modifiable request headers, unified review and task view, and task-level guardrails. ### Platform * **Unified Review & Task View:** Review items and tasks are now consolidated in the same list for improved visibility. * **Bug Fixes:** Multiple visual and functional improvements on Job and Workflow listing pages. * **Manhours Display:** Adjusted yearly Pro subscription pricing logic. ### Builder * **External Service Headers:** The system now allows modification of request headers within External Service settings, supporting dynamic variables for greater flexibility. * **Human Intervention Indicator:** A new status has been added to identify workflows that require manual review or action. * **Workflow Connectivity:** Fixed an issue where certain workflows displayed as incomplete or partially connected. * **Output Object Restoration:** The "Object" type has been reintroduced in Workflow Generation outputs to accommodate a wider range of workflow prompts. * **Enhanced Workflow Execution:** Resolved a problem affecting workflows that triggered sub-workflows containing files. * **Smarter Workflow Outputs:** Linked variables now maintain consistency more reliably in edge cases when opening and closing Workflow Output. * **Seamless Validation Experience:** Improved handling of edge cases involving false and 0 variable values, reducing validation errors. * **Task-Level Guardrails:** Implemented smarter safeguards that prevent the Run button from becoming active until all required inputs are supplied. ### Notifications * **Organization & Workspace Updates:** Expanded notification coverage for organization-level changes and workspace modifications. # v0.90 Beta (Oct 16, 2025) Source: https://developer.opus.com/release-notes/opus-v0-90-beta Released Oct 16, 2025. Minor Custom JSON payload definitions for external integrations, standardized date/time formats, and faster job listings with improved pagination. ### Platform * **Navigation Improvements:** Introduced a "Clear all filters" button across all pages and added "View in Builder" option on workflow lists. * **Standardized Formatting:** Dates and time formats are now standardized across all list views (Workflows and Jobs). * **Streamlined Job Creation:** System now auto-skips the workflow selection step; duplicated jobs navigate directly to input addition. * **Page Rename:** Job input page renamed to "Add Job Info". * **Date Picker Fix:** Resolved issues where the clear button wasn't properly closing the picker and clearing filters. * **Progress Bar Fix:** Corrected disappearing progress bar on the final step of job creation flow. * **Template Snapshots:** Workflow snapshot data is now viewable on the Workflow Details Page. * **Performance Boost:** Job listings now load faster using improved pagination instead of infinite scroll. ### Builder * **Workflow Persistence:** Complex output mappings are now fully preserved across Builder sessions. * **Payload Control:** Added the ability to define custom JSON payloads for external integrations using manual variables. * **Human Review UX:** Comprehensive improvements to the Human Review flow. * **AI Schema Generation:** Enhanced reliability of AI-generated workflow schemas, reducing manual editing. # v0.91 Beta (Oct 21, 2025) Source: https://developer.opus.com/release-notes/opus-v0-91-beta Released Oct 21, 2025. Major Significant template expansion with 22,736 new public workflow templates added to the Work Knowledge Graph, plus critical file-handling fixes. ### Platform * **Workflow Template Expansion:** 22,736 new public workflow templates added to the Work Knowledge Graph. * **Integrity Improvements:** User-generated workflows now feature enhanced metadata with improved traceability for audit purposes. ### Builder * **File Upload Resolution:** Resolved a bug preventing users from uploading multiple files to single input variables. * **File Security Patch:** Fixed access issues affecting saved file variables when sharing workflows outside organizational boundaries. # v0.92 Beta (Oct 23, 2025) Source: https://developer.opus.com/release-notes/opus-v0-92-beta Released Oct 23, 2025. Minor API Keys now included in Core (free) plan, numerous API edge cases resolved, and more Builder guardrails added. ### Platform * **Core Plan Enhancement:** API Keys functionality has been added to the complimentary Core tier as a standard feature. ### Builder * **Workflow Integrity:** Multiple edge cases stemming from minimized workflow generation have been fixed. * **API Job File Stability:** A significant bug impacting API-triggered jobs processing specific file types was resolved. * **Input Data Validation:** An undefined variable error occurring in certain edge cases on linked inputs has been corrected. * **Execution Guardrails:** External Service now includes run-guards ensuring execution requires validated endpoint, credentials, and payload information. * **Variable Templating:** External Service now permits referencing input variables through Jinja templating syntax (`{{variable_name}}`) within request payloads. # v0.93 Beta (Oct 28, 2025) Source: https://developer.opus.com/release-notes/opus-v0-93-beta Released Oct 28, 2025. Patch Improvements to workflow management and task execution monitoring with new guardrails and loading indicators. ### Platform * **Filter Management:** Added a "Clear all filters" button across all listing pages for improved usability. * **Workflow Preview Templates:** Users can now access a preview of the workflow when navigating to the Workflow details page. ### Builder * **Task Execution Guardrails:** The "Execute workflow" action now includes run-guards for safer operations. * **Execution Monitoring:** A loading indicator displays when tasks are actively executing. # v0.94 Beta (Oct 30, 2025) Source: https://developer.opus.com/release-notes/opus-v0-94-beta Released Oct 30, 2025. Minor Preview file interface now includes a delete button, direct editing for Opus Code Tasks and External Service Tasks. ### Platform * **Onboarding Cleanup:** The team streamlined onboarding by eliminating unnecessary tooltips and incorporating additional relevant guidance steps. ### Builder * **Task Editing:** Direct editing is now available within the task interface for both Opus Code Tasks and External Service Tasks. * **Input File Management:** Users can now remove files through a new delete button in the preview file interface. # v0.95 Beta (Nov 4, 2025) Source: https://developer.opus.com/release-notes/opus-v0-95-beta Released Nov 4, 2025. Patch Workflow navigation improvements with new "View in Builder" button and refined file handling in the Builder. ### Platform * **Workflow Navigation:** A new button labeled "View in Builder" has been integrated into the workflow list page, enabling quicker access to Builder functionality. ### Builder * **OCR File Type Restriction:** The Text Extraction task now limits accepted file formats to four types: PDF, PNG, JPEG, and JPG. # v0.96 Beta (Nov 6, 2025) Source: https://developer.opus.com/release-notes/opus-v0-96-beta Released Nov 6, 2025. Patch Improved workflow creation with enhanced prompt suggestions and better user visibility into task execution. ### Platform * **Enhanced Prompts:** The suggested prompts feature during workflow creation has been improved to represent more accurate workflows. ### Builder * **Execution Monitoring:** A loading icon now displays when a task is actively running, providing clearer feedback to users. * **Credential Access Permissions:** Credentials are automatically removed from shared workflows when the receiving user lacks the necessary access permissions. # v0.97 Beta (Nov 11, 2025) Source: https://developer.opus.com/release-notes/opus-v0-97-beta Released Nov 11, 2025. Major Platform UI revamp with reconstructed dashboard, parallel execution support on workflows, and Opus Agent Advanced Mode. ### Platform * **Dashboard Widgets:** The Dashboard has been reconstructed to display workflow and job creation metrics, along with Reviews SLA compliance tracking. * **Task Page Redesign:** The Organization Task page now features a structured interface that clearly separates task descriptions from required actions. * **Man-Hours Visibility:** Remaining Man-Hours now display persistently in the top navigation bar for easier access. * **Job Status:** Introduced a new "Waiting" status for job executions that are pending review completion. ### Builder * **Parallel Execution Support:** Workflows can now execute parallel paths, allowing concurrent processing of independent tasks. * **Enhanced Guardrails:** Policy enforcement and input validation across workflow tasks have been strengthened. * **Opus Agent Advanced Mode:** The Opus Agent task now offers Basic mode for task blueprint generation and Advanced mode for custom task configuration. * **Workflow I/O Defaults:** Workflow Input variables now correctly link to Workflow Output variables by default. * **Long-Running Task Indicators:** Visual loading states now display for extended task executions. * **File Download Consistency:** File downloads are now available from any file preview window across the platform. * **Credential Management:** Fixed an issue with ghost credentials appearing when sharing workflows. * **Input Variable Defaults:** New tasks inserted between Workflow Input and existing agents now correctly default to Workflow Input variables. # v0.98 Beta (Nov 18, 2025) Source: https://developer.opus.com/release-notes/opus-v0-98-beta Released Nov 18, 2025. Minor Redesigned dashboard with key performance indicators and parallel execution support for workflows. ### Platform * **Dashboard Widgets:** The dashboard interface has undergone reconstruction to present key performance indicators including workflow metrics, job creation trends, and compliance tracking for review service level agreements. ### Builder * **Parallel Execution Support:** The workflow Builder now enables concurrent processing paths, allowing independent tasks to execute simultaneously rather than sequentially. # v0.99 Beta (Nov 25, 2025) Source: https://developer.opus.com/release-notes/opus-v0-99-beta Released Nov 25, 2025. Major New waiting job status for executions requiring human review, redesigned sidebar menu with collapsible functionality, and file attachments for Agentic Reviews. ### Platform * **Workspace Filtering:** The dashboard now enables users to filter content by workspace. * **Enhanced Usage Tracking:** Manhours usage displays additional information including user details and descriptions. * **Redesigned Navigation:** The sidebar menu was replaced with a new design, with collapsible capabilities. * **Header Visibility:** Remaining Manhours are now displayed in both the header and Plan & Usage page. * **Job Status Addition:** A new waiting status has been introduced for executions pending human review. * **Profile Management:** Users can upload, update, and remove profile pictures. * **Task Filtering:** Task lists now support filtering organized by workspace. ### Builder * **File Attachments:** Agentic Reviews now accept file attachments. * **Autosave Fix:** Corrected autosave behavior for file type modifications in workflow inputs. * **Human Decision Overrides:** Users can now modify values within the Human Decision Task. # v1.0 (Nov 28, 2025) Source: https://developer.opus.com/release-notes/opus-v1-0 Released Nov 28, 2025. Flagship New onboarding page introduced to guide users through workflows, jobs and reviews. Added support for OpenAI GPT-5.1, Opus 4.5, and Anthropic models. ### Platform * **Filtering Logic:** The task filtering system was redesigned to resolve existing problems, including the addition of a status filter capability. * **Policy Page UI Revamp:** Policy listings were updated to maintain visual and functional consistency with other listing pages. * **Help & Compliance:** Support links (Terms, Privacy, Status, Release Notes, and Help) are now accessible from the login page footer. * **Workspace Selection:** Users can now select their workspace during workflow generation using recommended prompts. * **Enhanced Onboarding Experience:** A new onboarding page guides fresh users through workflows, jobs, reviews, and team member invitations. ### Builder * **Workflow Deactivation:** Workflows automatically transition to inactive status when errors or action items appear. * **Task Dependency Logic:** Task run buttons become disabled if parent tasks contain issues, requiring issue resolution or link removal before execution. * **LLM & Model Support:** Added compatibility for OpenAI GPT-5.1, Opus 4.5, and Anthropic models including Haiku and Opus variants. # v1.01 (Dec 11, 2025) Source: https://developer.opus.com/release-notes/opus-v1-01 Released Dec 11, 2025. Minor Users now have the flexibility to instantly revert changes made by the AI Assistant, plus unified resource hub and streamlined referral sharing. ### Platform * **Unified Resource Hub:** The sidebar includes dedicated navigation buttons directing users to Opus Release Notes, Academy, the Main Website, and System Health resources. * **Streamlined Referral Sharing:** A direct action for sharing referral codes is now available on the sidebar card, labeled "Copy Referral Link". * **Consolidated Organization Management:** Workspace settings have been repositioned to the top level of the Organization dropdown menu for easier access. ### Builder * **AI Assist Undo Functionality:** Users can now instantly reverse modifications implemented by the AI Assistant during their workflow. # v1.02 (Dec 18, 2025) Source: https://developer.opus.com/release-notes/opus-v1-02 Released Dec 18, 2025. Minor Improved workflow execution transparency with explicit 'Queued' status message, enhanced Job Details page, and interactive dashboard analytics. ### Platform * **Enhanced Job Insights:** The Job Details page has been redesigned for better visibility of execution inputs and outputs. * **Targeted Policy Management:** New filters for Status, Category, and Date range are now available on the Policies page. * **Direct Trust Center Access:** A new icon in the bottom-left navigation links directly to the Opus Trust Center. * **Consistent Navigation:** The Workflow Details page layout now aligns with other platform detail views. * **Interactive Dashboard Analytics:** Dashboard graphs are now clickable, enabling direct navigation to relevant record lists based on selected data points. ### Builder * **Real-Time Queue Transparency:** Workflows now display a clear "Queued" status message upon submission for execution. # v1.1 (Jan 15, 2026) Source: https://developer.opus.com/release-notes/opus-v1-1 Released Jan 15, 2026. Major Introducing Enterprise Generation, AI-powered Workflow Insights, and support for thousands of native Integrations. ### Platform * **Integrations:** Opus now supports thousands of native integrations, allowing you to seamlessly connect your workflows with external services. * **Enterprise Generation:** When creating a new organization, Opus can now generate a digital replica of your enterprise by analyzing your industry context and automatically provision hundreds—or even thousands—of industry-specific workflows with a single click. * **Enterprise Digital Twin View:** A new high-level visualization that maps relationships across workspaces, giving you a comprehensive view of how workflows connect throughout your organization. * **Job Duplication:** Improved reliability for job creation, and made it easier to duplicate jobs across all active workflows. * **Workflow Insights:** AI-powered insights are now available in the Workflow Details view, featuring five evaluation areas with actionable recommendations to optimize your workflows. * **Workflow Generation Visibility:** Users can now track workflows as they move through lifecycle stages during generation, making it easy to monitor multiple workflow generations in parallel from a single listing view. ### Builder * **Enhanced Integrations Task:** The Integrations task builds on the existing import and export capabilities, evolving them into a unified workflow task with cleaner design, better reuse, and improved visibility within the Builder. * **Enhanced Variable Optionality:** Greater control over required and optional inputs for Workflow Input Tasks, with consistent handling of nullable and required values across nested workflows. # v1.2 (Jan 20, 2026) Source: https://developer.opus.com/release-notes/opus-v1-2 Released Jan 20, 2026. Minor Opus launched in AWS Marketplace and real-time progress tracking during workflow and blueprint generation. ### Platform * **AWS Marketplace:** Launched Opus on the AWS Marketplace for direct subscription and billing. * **Workflow Generation:** Added real-time progress tracking functionality across listing views during workflow and blueprint generation. ### Builder * **Integration Tasks:** Implemented automatic clearing of integration credentials in re-shared workflow links and added a visible credential exposure warning flag. * **Parallel:** Implemented parallel execution for OCR tasks to reduce processing time. # v1.3 (Jan 23, 2026) Source: https://developer.opus.com/release-notes/opus-v1-3 Released Jan 23, 2026. Minor New actions added to X and Gmail integrations. ### Platform * **X (Twitter) Integration:** Added a Create Tweet action. * **Gmail Integration:** Added Watch Message, Get Message, and Get Message Attachment actions. # v1.4 (Jan 29, 2026) Source: https://developer.opus.com/release-notes/opus-v1-4 Released Jan 29, 2026. Major Code Library added with hundreds of thousands of utilities, workflow origins and upgraded OCR capacity as well as more integrations. ### Platform * **Code Library:** Added new reusable code utilities for list operations and data format conversions. * **Workflow Origins:** Added origin tracking to the Workflow Details page (Manual, Prompt-generated, Shared, or Enterprise Generation). * **Adobe PDF Services Integration:** Added an integration via Adobe PDF Services API to extract text, tables, and document structure from PDFs into JSON format. * **Gmail Integration:** Added multiple file attachment support to the Send Email action. * **Archive Workflows:** Added functionality to archive and unarchive inactive workflows from the Listing and Details pages. * **Tasks Reviews:** Redesigned the Task Details page to include specific fields for objectives, acceptance criteria, and required fix steps. * **Jobs:** Updated the Jobs Details page with an execution timeline, clear input/output visibility, and a new job creation side dialog. ### Builder * **Text Extraction:** Upgraded OCR service to support 10x processing capacity. * **Custom Agent Task:** Added compatibility and support issues with Gemini models. * **Code Task:** Added a new Code Task node to execute helper utilities from the Code Library directly within workflows. # v1.5 (Feb 16, 2026) Source: https://developer.opus.com/release-notes/opus-v1-5 Released Feb 16, 2026. Major Added Scopes to Integrations and Code Library, export functionality for Billing & Usage and support functionality to process multiple files as a single input. ### Platform * **Code Library:** Added Organization and Workspace scoped access controls for code utilities. * **Jobs:** Added support for uploading multiple files simultaneously during job creation. * **Integrations:** Added Organization and Workspace scoped access controls for new integration connections. * **Slack Integration:** Added four new actions: Create Channel, Invite Members to Channel, Create Canvas, and Edit Canvas. * **Workflow Insights:** Updated the UI to support versioning, allowing users to track changes in recommendations across workflow iterations. * **Billing & Usage:** Added export functionality for utilized man-hours and a usage breakdown per workspace. * **Tasks:** Standardized filtering and statuses. Added support for multiple file uploads and the ability to assign tasks to other organization members. * **Slack Integration:** Added Create Channel, Invite Members, Create Canvas, and Edit Canvas actions. ### Builder * **Human Review Task:** Added the display of rejection comments directly within the Human Review Task dialog. * **Text Extraction Task:** Added support for processing multiple files as input in a single step. * **Execute Workflow Task:** Implemented automatic locking for sub-workflows linked to a parent workflow to prevent unintended variable or task modifications. * **Workflow Variables:** Added auto-save functionality triggered upon input variable name entry. * **Human Task Outputs:** Added support for both single and multiple file variables as outputs. # v1.6 (Mar 3, 2026) Source: https://developer.opus.com/release-notes/opus-v1-6 Released Mar 3, 2026. Major Workflow Creation now supports file attachments, enabled verified organizations to build their own custom integrations and code utilities. ### Platform * **Organization Verification:** Added verification status for organizations to enable access to custom integrations and custom code utilities. * **Organization Settings:** Added AI Maturity Level settings to control the degree of automation during workflow generation. Added Data Sensitivity Controls to configure the handling of sensitive data and integration tasks during generation. * **Integrations:** Enabled verified organizations to create and manage custom integrations via GitHub, with access scoped to the Organization or Workspace level. * **Code Utilities:** Enabled verified organizations to build and link custom code utilities via GitHub, with access scoped to the Organization or Workspace level. * **Custom Integration Management:** Added full create, read, update, and delete capabilities for custom code utilities and integrations. * **Search & Filters:** Added optional search inputs to filters to improve query speed and accuracy across listing views. * **File attachment during Workflow Creation:** Added file attachment support for workflow generation. * **Insights Regeneration:** Enabled independent regeneration for Score or Policy insights. Added real-time progress indicators and contextual prompts for workflow version changes. ### Builder * **Security Enhancements:** Implemented backend security updates to protect workflow configurations and associated data. # v2.0 (Jun 2, 2026) Source: https://developer.opus.com/release-notes/opus-v2-0 Released Jun 2, 2026. Flagship Introducing Opus v2.0 — a top-to-bottom reimagining of the platform. Highlights include a new ABAC role and permission model, a complete redesign of the UI/UX and onboarding process, a new Discovery pipeline, a unified Marketplace experience across Agents, Code, Integrations, and Human Tasks, Code Playgrounds, and Policy. ### ABAC — Platform and Governance * **Resource Guards:** Permission guards added for Workflows, Tasks, Cases, Reviews, Feedback, Policies, Apps, Integrations, Referrals, Credentials, Group Members, Organization Roles, Organization Workspaces, Organization Details, billing details, and etc. * **Resources:** All objects on the platform are now classified as resources, and each resource is tied to a specific workspace. To access a resource, a user must belong to the workspace the resource is tied to. * **System Roles:** A set of pre-configured system roles is available when inviting employees, split into Organization-level and Workspace-level; Organization-level roles are assigned by default and can be changed later, and Workspace-level roles are assigned at the time of invitation. * **Permissions:** A user's role is defined by the set of permissions they hold on each resource in the workspace. Each permission controls what the user can do with that resource — i.e. view, edit, or have full access. * **Custom Roles:** Where system workspace roles are not aligned with your ABAC requirements, custom roles can be defined and assigned to users (subject to permission). ### Builder — Workflow Builder Rewrite * **Real-Time Collaboration:** The new builder version allows collaboration in a multi-player mode with live chat and cursors on canvas. Scoped execution is now enabled so private and public data execution coexist within a collaborative experience. * **Workflow Version History:** New sidebar to browse past versions; selecting a past version puts the canvas into read-only mode and renders that version's nodes and edges. * **Workflow Execution History:** New sidebar to browse past execution results. * **Node-Level Execution Settings:** Allows specific configurations such as caching, retries, timeouts, value prioritizations, and I/O compliance enforcement. * **Run Guards:** Block Run button until all changes are confirmed and saved; node status indicators show queued state; execution view auto-switches when data arrives and falls back to public when it disappears. * **Execution Audit Timeline:** Node-by-node execution history component. * **Build Agent Multi-Instance Sessions:** Multiple AI agents can collaborate inside a single workflow via Opus Chat; Build Agent cursor and full-text cursor visualization for autonomous edits. ### Builder — Nodes, Variables and Execution * **Agent Nodes:** Improved Basic Opus Agent generation; built-in Agent Tool References are more accurate in Advanced mode; self-learning config toggle added. * **Code Node:** Generation guardrails restrict imports to the permitted package list. * **Execute Workflow Node:** New Execute Workflow node type with dedicated settings; auto-link correctly handles unavailable matching types; the Execute Workflow node instantly reflects newly created sub-workflows and includes search. * **Decision Edges and Routes:** Edge type added to new edges; route management, properties, and complement support added for decision edges; Decision Agent routing implemented. * **Node Input Caching:** Node outputs are reused when explicitly configured. * **Smart Routing:** A single node can follow multiple execution routes without requiring multiple decision nodes. * **Loop Execution Mode:** A node can process the elements of an input list one at a time, in parallel. * **Workflow Configurable Execution:** Retries, delays, prioritization, type compliance, default nodes, and task-fail control are now configurable per workflow. * **Workflow Resilience:** Execution resumes from the point of interruption rather than restarting. * **Governed Agent Execution Stack:** Every agent execution draws from prior traces, governed memory, skills, tools, and organizational context. ### Agents Marketplace and Playground * **Agent Playground:** A brand-new surface for building, generating, and testing agents interactively before connecting them to a workflow. * **AI Agent Generation:** Streaming chat interface generates agent configurations from natural-language prompts. * **Basic and Custom Editors:** Dedicated editors for Basic (system prompt + user prompt template) and Custom (advanced class) agent modes. * **Skills, Guidelines and Learnings:** New Guidelines and Learnings tabs added on agent detail pages. * **Off-Platform Agents:** Build Agents surfaced in My Agents alongside connected agents. * **Agent Insights:** New Insights tab and agent specialty display. * **Agent Skills, Guidelines and Learnings:** Structured execution methodology, behavioral rules, and policies enforced across platform, workspace, organization, and agent governance layers; generalized patterns extracted from executions, evaluations, and reviews. * **Judge Step in Agent Loop:** Guideline compliance and accuracy evaluation now occur in-loop. ### Design Time Memory * **Scoped Memory Architecture:** Knowledge partitioned by Workspace, Organization, and Platform to ensure relevance, privacy, and governance. * **Contextual Retrieval:** Agents receive only memory valid within their current scope and permissions. * **Hierarchical Resolution:** Local (Workspace) memory overrides Organization and Platform memory when conflicts arise. * **Composed Memory View:** Agents receive a dynamically constructed memory context combining relevant knowledge across scopes at design time. ### Integrations Marketplace (Code and Integrations) * **Unified Marketplace Pattern:** Agents, Code, Integrations, and Human Tasks now share a single marketplace pattern with three tabs (All, My, Archived), filters, infinite scroll, and a consistent connect-sheet experience. * **Connect-and-Create:** For code and integrations (no template required); credentials can be added directly from the integration connect sheet. * **Credential Secrets:** Render as password inputs with reveal-icon support. ### Human Tasks Marketplace * **Human Task Node:** New node type with dedicated settings, handler selection flow, and routes and properties on the node settings panel. * **Human Task Marketplace:** New marketplace surface with three tabs (All Tasks, My Tasks, Archived). * **Human Tasks Integration:** Supports human reviews and tasks from the Human Tasks Marketplace or custom nodes. * **Rename:** Formerly known as Human Tasks, now renamed to Jobs across navigation, copy, and detail pages; the Jobs panel redesigned. ### Discovery and Business Processes * **Natural-Language Process Discovery:** Business users can now define processes in natural language as well as with collaborative tools before turning them into an automatable workflow. * **Conversational Clarification Loop:** Before making changes that could significantly affect your process, the Opus Chat pauses to ask a clarifying question and lets you pick from a few suggested options. * **Real-Time Collaboration:** A multiplayer canvas shared across all collaborators; toast notifications when a collaborator adds or deletes a step; presence avatars to show users actively updating a process. * **Business Process Detail Page:** A new detail page with hero, version dropdown, status badge, and tabbed More Info section (Workflows, Interactions, Collaborators, Performed by, Versions). * **Business Process Listing:** Three metric tiles (Created, Draft, Approved); insights bar; and status and workspace badges across views, alongside the full list of processes being discovered. * **Process Metrics:** Business Process pages include performance metrics, giving users insight into activity levels and process outcomes. ### Shared Variables (formerly Environment Variables) * **Rename:** Environment Variables renamed to Shared Variables in builder copy. * **Root Navigation:** Variables page moved to root navigation; guards scoped from the workflow resource instead of organization details. ### Channels * **Email Agent Experience:** Shipped visual and interaction improvements across the email agent interface. * **Workflow Fetch via Email Agent:** Users can now fetch workflows via the email agent for a cleaner and easier frontend experience. * **Chat Agent Experience:** Shipped visual and interaction improvements across the chat agent interface. * **Workflow Fetch via Chat Agent:** Users can now fetch workflows via the chat agent for a cleaner and easier user experience. ### Scheduler * **Redesigned Page:** New Schedules page with card, table, and calendar views; filters for search, workspace, status, and date range; new schedule creation flow. * **Detail Page Redesign:** Matches the Cases detail page structure. * **Routing:** Redirect from the old Scheduled Jobs route to Schedules. * **Terminology and Copy:** Jobs renamed to cases across listing, configuration, and detail pages; job run replaced with case run in the Run Now subtext. * **Versions Tab:** Added to Schedule Details. * **Rename:** Formerly known as Jobs Scheduler; now located under the Channels section in the navigation bar. ### Policy * **Policy Inspector Integration:** Policies feature moved into the Govern section as a Policies tab; it redirects to the Policy Inspector agent page with the My Policies tab pre-selected. * **Policy Permission Guards:** ABAC policy permission guards enforced. * **Policy Group Scoping:** Scope selection for policy uploads (Organization, Group, Private) added. * **Workflow Policy Evaluation:** The Workflow landing page now includes Policy Evaluation panels with violations, proposals, and a regenerate button. ### Cases and Reviews * **Rename:** Jobs renamed to cases across the app. * **Workflow Snapshot:** Streaming workflow snapshot on the Case Details page. ### Workspace and Access Management * **Workspace Accuracy:** Settings correctly scopes workspaces to the active organization. ### Settings and Invitations * **Invitations Flow:** End-to-end revamp of the invitation flow, allowing users to seamlessly navigate through sign-up, email verification, and the invitation journey. ### Other * **HubSpot Integration:** New HubSpot Customer Support integration available for Opus V2, enabling customer support workflows to be connected and managed. # v2.1 (Jun 18, 2026) Source: https://developer.opus.com/release-notes/opus-v2-1 Released Jun 18, 2026. Major A broad update bringing AI-driven enhancements across Opus Chat and Discovery, deeper approval and collaboration controls in Business Process Discovery, a Process Details uplift, sub-workflow Human Interventions, and builder reliability improvements. ### Governance * **API Keys inherit the same role as user:** API keys now inherit the exact roles and permissions of the user who generated them, scoped to their assigned workspaces. This replaces the previous organization-wide access model and ensures API keys never exceed the generating user's own access level. Existing API keys have been automatically migrated, with no action required. ### Builder * **Sub-Workflows with Human Interventions:** Sub-workflows now support Human Intervention steps, enabling richer human-in-the-loop orchestration across nested workflows. * **Workspace Filtering:** Workspace-level filtering is supported, with workflow counts reflecting the active filter. * **Execution Settings Override:** Workflow Execution Settings act as defaults for new nodes, with node-level settings taking priority when changed. * **Execution Time Details:** Workflow execution time visibility has been enhanced with detailed execution metrics. ### Agents Marketplace and Playground * **More Consistent Agent Output:** Agent outputs are now more consistent across identical runs, with higher-end models delivering consistently high-quality output under comprehensive custom prompts. * **Build Agents Interactive After Process Discovery:** Build Agents remain fully interactive following Process Discovery redirection, supporting value entry, variable generation, and type changes. ### Integrations Marketplace (Code and Integrations) * **SharePoint Integration Extended:** The SharePoint integration has been extended with additional functionality. ### Discovery and Business Processes * **Graph Rendering on Interview View:** Graph rendering has been introduced for the Interview View, with path information surfaced directly on the view and correct landscape rendering of the process-view graph. * **Real-Time Business Discovery Updates:** Business Discovery updates reflect in real time across Canvas View and Interview View for newly signed-up users. * **Canvas View Synced to Chat Step View:** The Canvas View responds to the chat "step view" command with the correct focus and drawer behaviour. * **Consolidated Notifications:** The Canvas View header shows a single, consolidated notifications section, in sync with Interview View notifications and with de-duplicated session-join alerts. * **Improved Organize Steps:** The "Organize Steps" algorithm tidies steps cleanly. * **Direct-Link Access:** Business Process Discovery is reachable via a direct link. * **Interview View UI and UX Uplift:** The Interview View experience has been refreshed for clearer journey visibility and improved usability. * **Decision Step on Canvas View Uplift:** The Decision step on the Canvas View has been refreshed with improvements to clarity and configuration. * **Full Approval Lockdown:** Approval lockdown applies to all collaborators with a full ownership-change history; approved steps retain approval, the step list is locked against further additions, and the assignee is locked on the step card. * **Per-User Undo/Redo:** Undo/redo is scoped per user, with notifications to affected collaborators. * **Post-Approval Automation:** Cases can now be automated after assignee approval in Discovery. * **Guided Restricted Access:** Restricted users are guided to access Discovery solely via navigation. ### Channels * **Personalised Welcome on Opus Chat:** Opus Chat now greets each user by name and invites them with "What would you like to discover?" * **Voice Input on Opus Chat:** Opus Chat now supports voice input with a clear idle state, active recording, and the ability to cancel or submit a recording. * **Smarter AI Behaviours:** AI behaviours have been refined for smarter handling of unmatched inputs, discovery, ambiguity, and deviation paths. * **Decision-Step Rules:** A defined rule set now governs how decision steps behave within a process. * **Smarter File Handling:** Supported file types now let the AI identify process content or prompt the user when needed. * **Add and Reposition Steps via Chat:** Decision steps can be added directly through Opus Chat, and tasks can be repositioned through the chat agent. * **Safer Branching:** Decision-task branching preserves existing conditions when a new branch is added. * **Full-Process PNG Export:** Chat-triggered PNG export captures the full process rather than only the visible area. ### Workspace and Access Management * **Workspace Members Filters and Sorting:** The Workspace Members tab supports Status and Role filters and column sorting. * **Improved Invitations and Verification:** Users receive an email when invited to join one or several workspaces, plus a verification email when signing up for a specific organization. ### Platform Performance * **Enhanced Prompt to Process Performance:** The performance of Prompt to Process has been improved. # v2.2 (Jul 3, 2026) Source: https://developer.opus.com/release-notes/opus-v2-2 Released 3 July 2026. Major v2.2 introduces **Organization Structure** — a new way to model your real-world hierarchy inside Opus. The release also includes improvements across Discovery, Opus Chat, the Builder, and platform runtime. ### Organization Structure * **Org Levels:** Model your organization's hierarchy exactly as it is — define custom levels like Division, Department, or Team that mirror how your business actually operates. * **Org Units:** Populate every level with named units representing your real teams and departments. Opus finally knows where each user fits. * **Org Chart:** A visual, interactive view of your entire hierarchy at a glance. Drill into any unit to explore the structure nested beneath it. * **Resource Linking:** Tie business process workflows and other resources directly to the Org Unit that owns them. Accountability becomes instantly clear. * **Filter by Org Unit or Level:** Slice every list and view by Org Unit or Org Level to focus on exactly what's relevant to your team or department. ### Blueprint * **Org Units on the Blueprint:** The Blueprint now surfaces the owning Org Unit for every process — structure and ownership rendered in one striking view. * **Default Scope and Filters:** Open the Blueprint focused on what matters to you, and filter by Org Unit to zero in on a specific part of the business. ### Discovery and Business Processes * **v2.2-001 · Reliable Process Creation at Scale:** Processes create and load reliably at high volume, with consistent visibility across listings. * **v2.2-002 · Smooth Real-Time Editing:** Arrow connections remain stable for all collaborators while a user types in the side drawer. * **v2.2-003 · Edit Mode Permits Concurrent Connections:** While one user edits a node's fields, other collaborators can continue connecting nodes on the canvas in parallel. * **v2.2-004 · Existing-Name Suggestions:** The Performers, Departments, and Integrations fields suggest existing names as you type. * **v2.2-005 · Teams Involved Tagging:** The "Departments" field has been renamed to "Teams Involved" and now supports tagging multiple teams per process. * **v2.2-008 · Editable Process Description:** Descriptions can be added and edited directly on the Business Process Details page. ### Builder * **Sub-Workflow Creation in the Builder:** Sub-workflows can now be created directly from the builder. * **Tool Calling in Advanced Agents:** Tool calling is fully supported for Advanced-type agents. * **Variable IDs in Generated Code:** Generated code uses variable IDs accurately. * **Reliable Workflow Stop:** Workflow execution stops cleanly when a run completes, and stops automatically when a node fails. * **Precise Node Editing:** Edits land precisely on the node you're working on. * **Faster Workflow Version Saving:** Saving a new workflow version completes promptly. * **Single Action Listings:** Each action appears once in the list. * **Persistent Prompt in Node Inspector:** Prompts stay visible when the node inspector is expanded. * **Code Node Library Awareness in Agent Chat:** The Agent Chat panel respects the code node's supported library list when generating code. * **Filter Integrations by Workspace:** Integrations can be filtered by workspace. * **Clean Integration Status Layout:** Integration status and timestamp sit cleanly side by side. * **v2.2-009 · Independent Code Node Execution:** Code Nodes execute independently — the outcome of one node no longer affects other Code Nodes running concurrently. * **v2.2-010 · Code Node Reliability Under Heavy Load:** Code Nodes complete reliably even when the system is under significant load. * **v2.2-011 · Accurate Link Handling in Action Items:** Action Items display and resolve link references accurately. * **v2.2-012 · Accurate Tool Search in Advanced Agent:** Searching for a tool within the Advanced Agent's Tool Reference now returns the matching tool reliably. * **v2.2-013 · Environment Variable Runtime Reliability:** Environment Variables resolve consistently during workflow runtime. ### Channels * **v2.2-006 · Faster Speak-to-Type:** Voice recording (speak-to-type) initiates more quickly, with noticeably reduced latency. * **v2.2-007 · Smooth Speech Highlighting:** Text highlighting flows smoothly in sync with Opus's speech. # v2.3 (Jul 17, 2026) Source: https://developer.opus.com/release-notes/opus-v2-3 Released 17 July 2026. Minor **Introducing Org Unit Management** — the foundation of the Digital Twin. Model your organization by defining org levels, creating units, and connecting people and processes into one living picture of how your company really operates. Plus enhancements across Discovery, Technical and Business Canvas Views, and platform-wide reliability improvements. ### Discover * **Cleaner Canvas Editing:** Deleting a step now keeps every other step exactly in place on the Canvas View. * **Stable Large Processes:** Big processes stay stable throughout a session, keeping you signed in and working uninterrupted. * **Workspace-Scoped Discovery Resources:** Discovery resources can now be scoped to a workspace. * **Warmer Interview Start:** A refreshed welcome and interview-entry experience in Opus Chat, with context, invitations, and supporting files. * **Smarter Step Suggestions:** Steps suggested from an uploaded file can now replace existing steps on the Canvas View. * **See Your Collaborators:** View who's collaborating with you directly on the Interview View. ### Build * **Clearer Python Error Handling:** Opus Code (Python) now surfaces clearer, more helpful error messages. * **Files as Task Output:** A task can now produce a file as its output. * **v2.3-001 · Faster Prompt to Process:** Prompt to Process performance has been improved end-to-end. * **v2.3-002 · Reliable Code Node Execution:** Code Node runs now complete dependably without timing out. * **v2.3-003 · Dependable File Uploads:** Uploading files through the Code Node now works reliably. * **v2.3-004 · Agent Chat Code Node Library Compatibility:** The Agent Chat panel generates Code Node code using the supported library list. ### Run * **Case Execution History:** View the full execution history for a case. * **v2.3-005 · Faster API-Triggered Cases:** Cases triggered via API now execute as quickly as they do on the canvas. ### Govern * **Org Unit Management:** Expanded controls for Org Units — membership, access, a new people view, a to-be state, org-admin permissions, and invite roles. * **Builders Can Invite to Workspaces:** Workflow Builders can now invite members directly to a workspace. * **Organization-Level Blueprints:** Blueprints are now managed at the organization level. * **Smoother Invitations:** Invited users without an account are guided straight to registration. * **Polished Create Workspace Form:** Refined styling and layout on the Create Workspace form. ### Platform * **Redesigned Nodes:** A refreshed, clearer node experience on the Canvas View. * **Improved Connectors:** Connectors on the Canvas View have been uplifted for a smoother modeling experience. * **Upgraded In-App Support Chat:** The in-app support experience now runs on Salesforce Live Chat. * **In-Sync Resource Lists:** Opus resources stay aligned with what is available to the user. * **v2.3-006 · Improved Canvas Response Time:** The canvas responds quickly and consistently during editing and interaction, keeping sessions smooth. * **v2.3-007 · Responsive UI at Scale:** The interface stays responsive even with a large execution history. # v2.4 (Jul 31, 2026) Source: https://developer.opus.com/release-notes/opus-v2-4 Released 31 July 2026. Minor **A powerful step up for the Business Canvas.** Redesigned nodes, uplifted connectors, richer step editing, and a warmer, more reliable process discovery experience — so teams can model even the most complex processes with confidence. Plus account self-service in Govern, clearer workflow sharing in Build, and a canvas that stays smooth with many hands on it. ### Discover * **Redesigned Canvas Nodes:** A refreshed, clearer node design on the Business Canvas for a cleaner modeling experience. * **Cleaner Step Deletion:** Deleting a step keeps every other step exactly in place on the Canvas View. * **Cleaner Duplicate Detection:** Intermediate steps created from a file attachment no longer duplicate on the canvas. * **Undo on the Canvas:** Ctrl+Z now reliably undoes actions such as adding and deleting steps. * **Clearer Step Actions:** The step three-dot menu now clearly separates Clear Step and Delete Step, with a confirmation before delete. * **Streamlined Canvas Shortcuts:** Tidy Up is now available directly from the canvas menu for clearer, more discoverable access. * **Refined Tidy-Up Experience:** A cleaner pre- and post-organize experience on the canvas, across Business and Technical views. * **Refreshed Discovery Canvas Top Bar:** An uplifted top bar for clearer navigation while modeling. * **Multiple Start Points for a Process:** Model processes that begin from more than one entry point. * **Flexible Start & End Nodes:** Start and end nodes can now be added and removed as needed. * **Duplicate a Step in One Click:** Copy an existing step to avoid re-entering similar details. * **Editable Process Name:** Rename a process at any time, directly from the canvas. * **Cleaner Decision Step Editing:** Decision conditions are now edited in the step side drawer, keeping the canvas tidy. * **Multiple Steps per Decision Condition:** Add several steps under each condition of a Decision step. * **Smart Field Suggestions:** Performed By, Integrations, and Teams Involved fields suggest values from previously used entries. * **Smarter Step Suggestions from Uploaded Files:** Steps suggested from an uploaded file can now replace existing steps on the Canvas View. * **Suggested Steps Across Contexts:** Opus Chat now generates suggested steps that handle multiple context variables cleanly. * **Smoother Voice Interview Highlighting:** Step highlighting during Opus voice interviews now stays clean and consistent. * **Invite Members to Discovery:** Invite others directly into a process discovery. * **See Your Collaborators:** View who is collaborating with you directly on the Interview View. * **Warmer Interview Start:** A refreshed welcome and interview-entry experience in Opus Chat, with context, invitations, and supporting files. * **v2.4-003 · Refined Discovery Welcome:** A warmer, more contextual greeting when someone first joins a process discovery. * **v2.4-004 · Accurate Collaborator Names:** Every collaborator's name now displays correctly on the Interview View for all members in the session. * **Step-Level Comments in the Side Drawer:** See comments tied to each step directly in the step side drawer. * **Workspace-Scoped Discovery Resources:** Discovery resources can now be scoped to a workspace. * **Consistent Step Counts:** Step counts now match everywhere — listing, details page, and canvas. * **Reliable Duplicate & Archive:** Duplicating a Business Process brings all nodes across, archived processes are clearly reflected on cards, and archived processes are accessible from the listing. * **Process Name Sync:** Renaming a process updates the name across the Interview View and canvas immediately. * **v2.4-001 · Polished Business Process Metrics:** Refined metric text on the Business Process listing. * **v2.4-002 · Bulk Step Approvals:** Approve every step assigned to you in one action. * **Live Activity View:** The Activity tab updates in real time across the top bar and per step. * **Complete Activity Logging:** Step actions taken from Opus Chat now appear in the Activity log. * **Accurate Markdown Export:** Downloaded Markdown files now describe the business process precisely. ### Build * **Share Workflows to Run:** You can now share a workflow so others can execute it. A copy of the workflow's input variables and any sub-workflows comes along, so recipients have what they need to run it right away. By design, user-specific private variables stay with each user and are never shared, so everyone's credentials and personal configuration remain private and secure. ### Govern * **Self-Serve Account Deletion:** Members can now delete their own Opus account directly from settings, putting them in full control of their data. * **Reliable Sign-In Experience:** Business Processes and other organization-scoped data load correctly straight after signing in. ### Platform * **Uplifted Canvas Connectors:** Connectors on the Canvas View have been redesigned for a smoother modeling experience. * **Smoother Multi-Collaborator Sessions:** The Business Canvas stays responsive with many collaborators working on the same process. # v2.5 (Aug 13, 2026) Source: https://developer.opus.com/release-notes/opus-v2-5 Released 13 August 2026. Minor **Processes that travel, and workflows you can hand over.** Any discovered process can now be exported as standard BPMN and linked to the processes around it. Send a Copy hands a colleague a working workflow with its credentials already connected. The canvas keeps your layout, your assignments, and your comment threads exactly where you left them. Plus folders and ownership in the File Library, shared variables with model selection, and a dedicated set of API endpoints. ### Discover * **Export a Process in BPMN format:** Download any discovered process as standard BPMN output. Your process model opens directly in whatever modeling, documentation, or governance tool your organization already runs on, so the work you do in Opus is never locked inside it. * **Link Related Processes:** The More Info section of a process now shows the processes connected to it, and lets you link new ones. Where a process hands off to another, or shares an owner or a system with it, that relationship is visible from the details page rather than living in someone's head. * **Your Canvas Layout Stays Put:** Steps are organized automatically only the first time you open the canvas for a new process. Any arrangement you make by hand afterwards is preserved on every visit, so a layout you have deliberately laid out for a review is exactly as you left it. * **v2.5-001 · Process Status Matches Everywhere:** The status shown on the process listing, the details page, and the Blueprint now matches the canvas exactly, so a process that is approved reads as approved wherever you look at it. * **v2.5-002 · Workspace Filter on the Business Processes List:** Filtering the Business Processes list by workspace returns the processes belonging to that workspace, making it quick to narrow a long list down to one team's work. * **Room for Longer Step Details:** Fields in the step side drawer expand across multiple lines as you type. Long descriptions, detailed instructions, and multi-clause conditions stay fully visible while you write them and when you come back to read them. * **Clear Progress While Files Are Read:** When a large document takes time to process, the canvas now shows what is happening and how far along it is, so you know the upload is working and roughly how long you have to wait. * **Links as Step Information:** Step fields now accept links as stored information. Reference a policy document, a system of record, or a runbook directly on the step it belongs to, and anyone opening that step can follow it. * **Stable Step References:** Every step now carries a stable, unique identifier that stays with it for the life of the process. Steps can be referenced reliably from elsewhere in Opus and from your own systems, even as the process is edited around them. * **Step Icons That Fit the Step:** Icons on the discovery canvas are generated from each step's own title and description, so a glance across the canvas tells you what kind of work each step represents. * **Assignments Visible on the Canvas:** Assigned To is shown directly on canvas steps, and assignment notifications take you straight to the step that needs you. * **A Fuller Business Process List:** The Business Processes list now shows your full set of processes rather than the first page, so nothing is left below the fold on a large organization's list. * **Refreshed Process Creation:** The Business Process creation modal has an updated layout, making it clearer what each field is for as you set a new process up. * **Accurate Processes Assigned To Me:** The "Processes Assigned To Me" counter reflects everything currently assigned to you, so the number on your home page matches the list behind it. * **File Uploads for Process Collaborators:** Collaborators invited to a process can upload files to it, so supporting documents can come from whoever holds them rather than only the process owner. * **Lock In Reflected Immediately:** Locking in a step is reflected on the Interview View straight away, keeping the interview and the canvas in step with one another. * **Voice Input in Agent Chat:** Speaking to Agent Chat picks up your input directly and continues the conversation from where you are. * **A Smoother Welcome Flow:** Choosing "Just me for now" in the process discovery welcome flow advances you into the interview, and the "Invite teammates" option responds as expected. * **Readable Notification Titles:** Notification cards describe steps and branches in the same words you see on the canvas. * **Uninterrupted Collaborative Chat:** Opus Chat keeps responding throughout multi-user collaboration sessions, including after a re-login. * **Dependable Process Generation:** Generating a business process completes reliably. * **Full Editing for Organization Members:** Invited organization members can edit and approve any step in a business process, while unapproving a step stays with the member it is assigned to — so a step is only ever reopened by the person accountable for it. * **Persistent Process Descriptions:** A process description you enter stays saved. * **Reliable Decision Branch Mapping:** Pointing a Decision branch at End Process keeps every previously connected step intact. * **Precise Undo on Decision Paths:** Undoing a change to Then and Otherwise paths restores each path exactly as it was. * **Steady Canvas View While Collaborating:** Editing a step through chat keeps the canvas where it is for everyone else in the session. * **Accurate Blueprint Step Details:** The Blueprint details page shows correct approved-step counts along with Integrations, Collaborators, and Performed By. * **Threaded Canvas Comments:** Replies from chat append to the existing comment thread on the canvas. * **Comments in Order:** Comments on the Interview View read oldest to newest. ### Build * **Send a Copy, Credentials Included:** Sending someone a copy of a workflow now hands them something that runs. A copy staying inside the same workspace reconnects its integration nodes to the original credential. A copy crossing into another workspace gets its own clone of the credential, with ownership transferred to the recipient, and a **Share credentials with other workspaces** checkbox in the Share Workflow modal puts that decision in your hands at the moment you share. User-specific private variables stay with each user, as before. * **v2.5-003 · Clear Guidance When a Workflow Copy Is Blocked:** When a step in a shared workflow does not pass its security check, the copy stops and says so plainly instead of failing without explanation. The message confirms the share link itself is fine, points you to the person who shared it to adjust the workflow and send a new copy, and includes a trace ID to quote if you need help. * **Folders and Ownership in the File Library:** Files can now be organized into folders in the File Library, each with a clear owner. Organizations working with hundreds of documents can group them the way they already think about them, and it stays obvious who is responsible for each group. * **Shared Variables with Model Selection:** A shared variable can now carry a model choice, and nodes can receive shared variables directly. Set the model once at the workspace level and have every node that reads that variable pick it up, instead of setting the same model on each node in turn. * **Run a Single Node with Upstream Values:** Execute one node on its own while it pulls real values from the nodes linked before it. Testing a step in the middle of a long workflow no longer means running everything ahead of it, and the values the node receives are the ones it would get in a full run. * **Sub-Workflows from the Technical Canvas:** Create a sub-workflow directly from inside the technical canvas, keeping a large automation broken into pieces you can reason about. * **Text Extraction Keeps Your File Names:** Extracted documents are labelled with their actual file name instead of a generic `file N`, so it is always clear which document a result came from. * **OpenAI Web Search Integration:** Workflows can now search the live web through the OpenAI Web Search integration. * **See Where an Integration Is Used:** An integration now lists the workflows using it, so you can tell what a credential change will affect before you make it. * **A Predictable Ceiling for Code Nodes:** Code Node runs carry a default 60-second execution limit, so a script that will not finish stops promptly with a clear result rather than holding a run open. * **v2.5-004 · Agent Chat Generates Supported Code:** Code produced from the Agent Chat panel uses only the libraries the Code Node supports, so a generated snippet runs as it stands. * **Flexible Gmail Attachments:** The Gmail node accepts a single file as well as multiple files. * **Dependable Gmail Watch Variables:** The Gmail Watch Message node reads its Message ID and Max Results variables as configured. * **Loops Preserve Workspace Data:** Turning on a loop keeps all workspace data in place. * **Return to Your Workflow After Connecting:** Completing an integration sign-in returns you to the workflow you were building. * **Viewable Spreadsheet Output:** Spreadsheet files created by a Code Node open correctly for viewing. * **Accurate Prompts from Custom Models:** Custom model selections generate prompts accurately. * **Clearer Type Mismatch Messages:** A type mismatch during execution names the expected and received types precisely. * **Decision Nodes Copy Every Path:** Copying and pasting a Decision node preserves all of its paths. * **Model Choice Kept Across Agent Nodes:** Generating several agent nodes at once keeps each node's model selection, so a multi-agent workflow executes with the models you picked. * **See Which Workflow an Agent Is Linked To:** An agent's Workflows tab now lists the workflow it is linked to, so opening an agent detail page tells you straight away what it is wired into. ### Govern * **One Role per User:** Role management assigns a single, unambiguous role to each user. * **Settings Follow the Active Organization:** Switching organization refreshes organization settings. ### API * **A Versioned API:** The Opus API is now served on a versioned path, authenticated with an API key. Versioning lets new features and improvements arrive as backward-compatible changes, so your existing integration keeps working, there's a clear upgrade path when you want it, and you move to a newer version on your own timeline rather than ours. * **Workflow Generation Endpoints:** The workflow generation endpoints are now available on the versioned path, so you can generate a workflow programmatically from your own systems. # v2.6 (Aug 31, 2026) Source: https://developer.opus.com/release-notes/opus-v2-6 Released 31 August 2026. Minor **Discovery that several people can work in at once.** Locking now happens field by field, so a colleague can open the step you are already in and edit the parts you are not. Version history groups every change into a version you can browse and roll back to without losing where you came from, a minimap keeps large processes navigable, and process-level metadata — objective, volume, duration, systems, pain points — now has a side drawer of its own. Plus a reworked Members page with every outstanding invitation in one place, org-unit tagging across the File Library, and a handful of Builder conveniences: copy a node as Markdown, grab every variable at once, and dates that resolve at the moment a workflow runs. ### Digital Twin * **People Inside Every Workspace:** The Workspaces edition of the Blueprint shows the people who belong to each workspace as avatars within their slice, with admins nearer the centre. Undiscovered and no-access units can now be hidden through the same show-hide filter as any other unit. ### Discover * **v2.6-001 · Process-Level Metadata in Its Own Side Drawer:** Objective, business impact, frequency, estimated volume, total duration, teams, people, systems, abbreviations, key documents and pain points are now captured for the process as a whole, not just step by step. Most of it fills in automatically from the steps you have already described, and all of it stays editable from the Canvas View. * **v2.6-002 · Version History You Can Roll Back To:** Edits are grouped into versions built on top of the activity log. Browse what changed and who contributed, expand a version to see the individual edits inside it, and restore an earlier version when you need to. Restores are non-destructive — the state you came from is never lost. * **v2.6-003 · Durations as a Range, With Waiting Time Counted Separately:** A step can carry a minimum and maximum duration in whichever unit fits, and the wait between one step and the next is recorded independently of the time spent actually performing the work. Processes reflect how long things realistically take rather than a single optimistic figure. * **v2.6-004 · A Welcome Flow That Asks About the Process:** Before drafting your steps, Opus asks how often the process runs, roughly what volume it handles, what it is meant to achieve and what happens if it goes wrong. Anything it can already tell from your uploaded documents it confirms rather than asks, every question can be skipped, and the answers land straight in the process side drawer. * **v2.6-005 · Several People in the Same Step at Once:** Locking now works at field level rather than step level, so a colleague can open a step you are working in and edit the fields you are not. Only the exact field in use is held. * **Chat Respects the Same Field Locks:** Editing a step field through Opus Chat honours the field-level lock the canvas uses, so a value someone else is actively typing into is never overwritten from the chat side. * **v2.6-006 · A Minimap for Large Processes:** A minimap in the bottom-right corner of the Canvas View shows your whole process at a glance, with a marker for the part you are currently looking at. Click to jump somewhere, drag the marker to pan, scroll to zoom, or drag out a region to zoom straight into it. It is on by default, and once you change that the preference is remembered. * **Move Between a Process and Its Sub-Processes:** Linked sub-processes are reachable directly from the parent process, and back again, without leaving the canvas. * **v2.6-007 · Deleting a Step Through Chat Completes First Time:** Name the step you want gone and the deletion goes through. * **Reorder Steps on the Interview View:** Steps can be reordered directly on the Interview View, and removing a step using the Opus Chat suggestion chips completes as expected. * **Dependable Chat Actions:** Actions you ask for in Opus Chat apply to the canvas reliably. * **Build a Canvas From an Uploaded Document:** Applying a detailed process from a supporting document populates the canvas with the steps that document describes, replacing the placeholder steps you started with. * **Several Files at Once:** Uploading multiple supporting files together processes cleanly, and the conversation picks up correctly with single files afterwards. * **Decision Branches You Can Tell Apart:** Connections stay clearly distinguishable when a decision node carries several conditions. * **Chat Confirms Which Step It Is Changing:** When your prompt does not name a step, Opus asks which one you mean rather than quietly applying the change to whichever step happens to be selected. * **v2.6-008 · Downloads Named After the Process:** PNG and Markdown exports carry the process name in the filename, so a folder of downloads is easy to tell apart. * **v2.6-009 · Corrected Duration Label:** A spelling error in the Duration column under More Info has been fixed. ### Build * **v2.6-010 · Workflow Changes Save Reliably:** Edits made in the workflow builder persist as expected. * **The Current Date and Time at Runtime:** A toggle on Date types resolves to the moment the workflow actually runs, rather than a value fixed when you built it. * **Agent and Version IDs You Can Copy:** The agent version table shows both the agent ID and the agent version ID with a copy action, the same way workspace and organization IDs already work. * **Copy Node Content as Markdown:** A button on each node copies its content as Markdown, ready to paste into a document or ticket. * **Copy Every Variable at Once:** A single action on a code node copies its full set of variable names and IDs. * **v2.6-011 · Reliable OCR on PDFs:** Optical character recognition completes on PDF inputs instead of stopping with an internal error. * **Large File Batches:** The input node accepts batches well past its previous ceiling, so uploads of 150 files and more go through. * **Lists as Integration Inputs:** Using a List as an input variable type on an integration node works as expected. * **Date Formats Survive Execution:** A custom date format configured in the builder is kept through the run rather than being replaced with the standard ISO format. * **v2.6-012 · Every Branch Out of a Sub-Workflow Is Visible:** Multiple conditional outputs from a sub-workflow node are drawn distinctly instead of overlapping on a single point. * **Sub-Workflows Keep Their Configuration:** Creating a sub-workflow from inside the technical canvas preserves the integration and code node configuration it contains. * **Output Variables Listed With Inputs:** Selecting a node shows its output variables alongside its inputs. * **Reused Marketplace Agents Keep Their Instructions:** Pulling an agent back in from the Agent Marketplace carries its original instruction and detail rather than arriving blank. * **Agents Connect for New Users:** A newly signed-up user can connect and configure an Agent node from the Agent Marketplace straight away. * **Told When a Node Cannot Ingest:** The builder tells you when a node fails to take in its input, rather than leaving the outcome unclear. * **Readable Integration Validation:** Configuration problems on an integration are explained in plain language instead of surfacing as an internal error. * **Flexible Web Search Model Names:** The OpenAI Web Search integration accepts model names in any casing. * **Distinct Files From Code Nodes:** Generating a file from a code node with a variable name produces the correct file each time. ### Run * **Assign Human Review to Process Owners and Job Reviewers:** Human Review tasks can be assigned to both roles. * **v2.6-013 · Accurate Execution Timings:** Long-running executions report their real duration on the Cases view rather than a repeated fixed value. * **Create a Case Wherever Workflows Are Active:** The create-case flow finds your organization's active workflows instead of reporting that none exist. * **Connected Code Utilities:** An active connected Code Utility now redirects to the right workflow URL. Every workflow where Code Utilities are used is listed on the Workflows tab. ### Optimize * **Regenerate Score and Policy Insights:** Regenerating a score or a policy insight completes rather than failing quietly. * **Agents Recover From Malformed Output:** When a model returns output an agent cannot read, the agent falls back cleanly instead of failing the run. * **Agent Skills Resolve During Execution:** The skills active on an agent are picked up correctly while it runs. ### Govern * **A Reworked Members Page:** The members table now shows each person's organization role and org unit, and clicking anywhere on a row opens their details. A second tab lists every outstanding invitation across the organization — pending, expired and declined — with resend and revoke on each. * **A Full History of Access Changes:** Every invitation, role change and workspace addition or removal is now retained, so how someone came to have the access they have is answerable. * **Resent Invitations Carry the Updated Role:** Change a role before resending an invitation and the new role is what gets applied on acceptance. * **One Role by Default:** A new user in the central workspace receives a single appropriate role rather than several at once. * **Tag and Filter the File Library by Org Unit:** Files and folders can carry one or more org unit tags, shown as badges in both list and grid views, so a large shared library narrows down to one department's documents in a click. Uploader profile pictures now appear on file cards too. * **Organization Switches Handled Across Tabs:** Switching organization in one tab no longer leaves resources open in another tab showing an error, and the policy tab stays available afterwards. ### API * **Process Detail and Organization Integration Setup Endpoints:** New endpoints return the full detail of a discovered process, and create integrations and credentials at organization level. # v2.7 (Sep 14, 2026) Source: https://developer.opus.com/release-notes/opus-v2-7 Released 14 September 2026. Minor **Discovery makes more of what you already have.** Upload your existing process documents and Opus reads them closely — keeping what belongs to your process, settling duplicate wording, filling in the owners a document supports, and grouping steps into named phases. Where two documents tell different stories, it asks you first, so the draft you get reflects how the process really runs. The same instinct carries into the conversation: describe a step that is really another team's process, and Opus offers to make it a sub-process — linking the one that already exists, or creating it ready for its owner to pick up. Either way you keep going without breaking out of the flow. Around that, the Code Node editor has been reworked, the discovery canvas has picked up keyboard shortcuts, and a Share Feedback control now sits on every major surface. ### Discover * **v2.7-001 · Sub-Processes Without Leaving the Conversation:** When you describe a step that is really another team's process — you name the team, say you don't know what happens inside, or call it by name — Opus offers to mark it as a sub-process. From there it links the existing process if it can find one you have access to, or creates a new one for someone else to pick up, without redirecting you. Once a step is a sub-process, Opus stops asking what happens inside it and asks where your process picks back up instead. * **v2.7-002 · Better Drafts From Your Documents:** Uploaded documents now go through a repair pass before Opus drafts anything. Steps belonging to unrelated departments are filtered out, near-duplicate wording is resolved, missing owners are inferred as a role or department only where the document supports it, and steps are grouped into named lifecycle phases. Contradictions **between** documents — a step with two different owners, or one documented in practice but absent from the official procedure — are raised one at a time before any draft appears, rather than being silently resolved. * **v2.7-003 · Ask Opus What Is on the Canvas:** Request a summary of the process as it currently stands and Opus describes what is there — the domain it covers and its steps grouped into phases. * **v2.7-004 · Keyboard Shortcuts on the Canvas:** The shortcuts for canvas actions are now discoverable from the canvas itself. * **v2.7-005 · An Email When a Step Is Assigned to You:** Being assigned a step in a process now sends you an email, so work reaches you without your having to watch the canvas. * **v2.7-006 · Assign Several Steps at Once From Chat:** Ask Opus Chat to assign a set of steps to someone and all of them are assigned together. * **One Team per Step:** A step maps to a single team, keeping accountability for each step unambiguous. * **Systems, Not Integrations:** Discovery consistently says "Systems" for the tools a process runs on, matching how the business describes them. * **Notifications Say Who Assigned the Work:** A multi-step assignment notification names the person who assigned it. * **v2.7-007 · The Speak Button Reads Only What You Asked For:** Playing a message aloud stops at the end of that message instead of continuing into the ones after it. * **v2.7-008 · Clearer Wording on Step Actions:** The "Repositioned" action now says what it did. * **v2.7-009 · A Clear Message When Colleagues Are Already in a Process:** Opening a process other people are working in explains what you are seeing, instead of a message that does not match the situation. * **A Refreshed Canvas Toolbar:** The bottom toolbar on the discovery canvas has an updated design. * **Attach Files From Chat:** "Add files" in chat opens the uploader directly. * **Export the Canvas as an Image:** PNG and SVG exports of the process canvas complete successfully. * **Approval Counts That Add Up:** Listing cards show approved and total step counts from a single source, so a count like "15 of 14" cannot occur. * **Live Step Counts:** The step count on the Business Processes listing updates as steps are added and removed. * **Dependable Process Rebuilds:** Rebuilding a process keeps anchor names, wires decision branches correctly, and leaves no duplicate connections or orphaned edits behind — including when several people have been editing. * **A Steady Canvas While Commenting:** Adding the first comment in a comment box keeps the canvas where it is instead of re-centring on the comment. * **Decision Cards Stay Open:** Mapping a Then or Otherwise block keeps the decision card open so you can finish configuring it. * **Process Links Work Across Organizations:** Opening a business process link while in a different organization takes you to the process. * **Collaborators See the Process:** An invited user opening a business process sees its details rather than an empty page. * **Approved Processes Stay Settled Once Automation Starts:** After automation has begun, steps cannot be edited through chat without explicitly reopening the process first. * **Reliable Discovery on Large Processes:** Long or complex processes complete their conversation with Opus without interruption. ### Build * **A Reworked Code Node Editor:** The code editor has been updated, and find-in-file works as expected inside it. * **Custom Headers on Off-Platform Tasks and Reviews:** An off-platform task or review can carry an optional custom header, and its payload has been reduced so it travels efficiently. * **Test a Step With Real Upstream Values:** Re-running a single node picks up the latest output from the nodes before it rather than a stale cached value. * **Share Feedback Where You Are Working:** A Share Feedback control now sits on the discovery canvas, in Build chat, on the workflow canvas, in the discovery chat and interview, and in the global navigation, so a reaction reaches us from the surface that prompted it. * **v2.7-010 · Caching Inside Loops:** Cached values are reused correctly across loop iterations. * **v2.7-011 · Concurrent Workflows Stay Separate:** Two workflows running at the same time keep their outputs to themselves. * **v2.7-012 · Conditional Steps Take One Branch:** A conditional step follows either its true or its false path, never both. * **Human Tasks Run the Workflow You Saved:** A human task executes against the current saved state of the workflow. * **Agent Models Kept Current:** The model selector on an agent node reflects the models actually available. * **Inactive Sub-Workflows Cannot Run:** A sub-workflow that is not active is not executed. * **Generate Value Produces a Value:** The Generate Value action on a node variable returns a value. * **Integration Versions Visible After Editing:** The version of an integration is shown in the builder once it has been edited. * **Variable Links Survive Generation:** Variables stay linked after a workflow is generated with AI. * **Accurate Variable Counts:** The variable count shown in Link to Node matches the variables available. * **Auto-Link Accepts Compatible Types:** Auto-link now matches against the types a field allows, instead of requiring an exact match on both ends. * **Readable Tool References:** Tool reference tiles show enough detail to identify what they point at, and results scroll in one direction. * **Plain-Text Code Descriptions:** A code's description renders as text on its detail page. * **Full Names on Cases:** The Cases tab shows complete names under Created By and Run By. * **Consistent Component Wording:** Component cards use one term for the number of connections they have. * **Stay Signed In Through Google Sheets Sign-On:** Connecting Google Sheets from the builder keeps your Opus session, including when Google asks you to rotate your password. * **Easier Editing on Node Inputs:** The active editing area on a node's Input field is comfortably clickable regardless of how short the current value is. * **Archive Only What Can Be Archived:** The archive action is unavailable on active workflows. * **Arrow-Key Navigation:** Up and down arrow keys work as shortcuts. ### Run * **Open a Case From Its Name:** Clicking a case name on the workflow details page opens that case. ### Govern * **v2.7-013 · Honest Feedback When Re-inviting Someone:** Sending a fresh invitation to someone whose invitation is still pending now tells you what actually happened, instead of confirming success without sending anything. * **v2.7-014 · Email Addresses Pasted From Anywhere:** Invisible characters that travel with an address copied out of a document or a chat message no longer stop an invitation reaching the right person. * **v2.7-015 · API Key Creation on the Pro Plan:** Organizations on the Pro plan can create the API keys their plan includes. * **Simpler Role Labels:** Organization Admin and Organization Member now read as Admin and Member. * **Reuse the Names of Deleted Org Units:** A name freed by deleting an org unit can be used again. * **Land in the Right Organization After an Invitation:** Accepting an org unit invitation takes you into the organization it belongs to. * **Read-Only Access Clearly Marked:** Access Management distinguishes a read-only System Role from an editable one, and locked fields on an Org Unit no longer present an active-looking dropdown. * **Consistent Required-Field Marking:** Creation modals mark their required fields the same way throughout Settings. * **A Clearer Current-Page Indicator:** The marker for the page you are on in the Settings sidebar no longer reads as an unread notification. * **Accurate Setting Descriptions:** Review Intensity carries its own description, and the role shown on an invitation landing page matches the role in the invitation email. ### Platform * **A Warning Before You Hit the Character Limit:** Every text entry point tells you when your input approaches the 20,000-character ceiling, rather than truncating without notice. * **Notifications Retried Reliably:** A notification that needs retrying is delivered on the retry. * **Consistent Typography:** Fonts are consistent across every page. # v2.8 (Sep 29, 2026) Source: https://developer.opus.com/release-notes/opus-v2-8 Released 29 September 2026. Minor This release is about getting your work out of Opus and into the rest of your business. You can now download a process definition document for any process, share processes between workspaces, and drive workflows and agents through a public API. Process discovery also gets a broad round of polish: chat can add notes, branch after a decision, and invite colleagues at any point in the process — not just the first time. ### Discover * **Your own words shape the opening step:** When you describe a process in your own words instead of accepting the recommended steps, the first step now updates to match what you wrote. (v2.8-001) * **Invite a colleague straight from a comment:** Tagging someone's email address in a comment, whether on the Canvas View or on an individual step, now invites them into the process discovery. (v2.8-002) * **An email when you are tagged:** Being tagged in a comment on a business process now sends you an email, so a question left on the canvas reaches you even when you are not in Opus. (v2.8-003) * **Share processes between workspaces:** A process discovered in one workspace can now be shared with another, so teams that work across workspaces build on each other's work instead of starting again. (v2.8-004) * **Export the canvas as an image:** Exporting a process canvas to PNG now completes reliably. (v2.8-005) * **Download a process definition document:** Any process can now be exported as a PDD, ready to circulate to people who do not work in Opus. * **Rename a process from its details page:** Process name and description are now editable directly on the process details page. * **Add notes to a step from chat:** Opus Chat can now add comments and notes to a discovery step for you. * **Branch into parallel steps from chat:** You can now ask Opus Chat for parallel steps after a decision node. * **Invite people from chat at any time:** Inviting existing or new users through chat now works throughout the life of a process, not only on the first invite. * **Sharper file imports:** Imported documents produce a higher-fidelity draft, and the clarifying questions Opus asks in the file timeline no longer block you while it works. * **Editing an automated process picks up where it should:** "Make edits to the process" now includes the unapproval and step-picking flow after automation has started. * **Step details replace cleanly:** Replacing the detail on a step now overwrites the previous value instead of appending to it. * **Approvals stay true:** Steps no longer carry approvals forward from an earlier state, so a step never shows as approved when it is not. * **Decision branches keep their order:** Editing the target of a decision branch no longer reorders the branches. * **Start nodes can be added and removed from chat:** Adding a new start node through chat is now supported, and deleting one completes instead of stopping after the confirmation. * **Consistent process names:** Generated process names now follow one naming format throughout. * **Fuller filtering on the process list:** The process list now offers Org Level, Org Unit, Approval Date and Duration filters. * **Collaborators start in the Interview View:** Opening a new process as a collaborator now takes you to the Interview View rather than dropping you onto the Canvas View. * **Step assignment emails open the Canvas View:** The "View Process" button in a step assignment email now opens the Canvas View. * **See everyone on a step:** The Performed By field now shows avatars whether one person or several are assigned. * **Chat confirms when a tidy-up finishes:** Asking Opus Chat to tidy the layout now ends with a clear confirmation in the conversation. * **Field locks cover process details:** The locks that stop two people editing the same field at once now extend to process-level metadata in the details drawer. * **Feedback from any chat:** Chat feedback is now available. ### Build * **Long numbers survive the object builder:** A string made up of digits now keeps every character when built into an object, instead of being cut short. (v2.8-006) * **Base64 file inputs accepted:** Files supplied to a workflow as base64 are now read correctly. (v2.8-007) * **Duplicated workflows run their agents:** An agent inside a duplicated workflow now runs exactly as it does in the original. (v2.8-008) * **Token limits on agent nodes:** Agent node settings now include Max Input Tokens and Max Output Tokens. * **A clearer agent node:** The agent node on the canvas has been reworked for legibility. * **An integration picker you can scan:** The integration picker is now a vertical list rather than a horizontal card scroll. * **Code editor keys behave:** Tab now accepts an autocomplete suggestion, and Esc closes the suggestion rather than the whole Node Inspector. * **Types hold inside agent loops:** Nodes executed within an agent loop now handle their input and output types correctly. * **Workflows built from chat arrive complete:** A workflow generated by the chat agent now comes through with every node connected and configured. * **Keep talking to the agent while you edit:** Issuing a command to the chat agent during a workflow edit no longer cancels the run. * **Prompts stay put:** System prompts and node prompts persist reliably. * **New credentials activate first time:** Creating a credential now completes without an activation error. * **Generation continues onto the canvas:** Workflow generation now runs as expected after you are redirected to the canvas. * **Unresolved items hold back execution:** The Execute Workflow button stays disabled while a workflow still has unresolved action items. * **A clear word on type mismatches:** Mapping an object or a list into a workflow output node now explains the type mismatch rather than failing quietly. ### Run * **A simpler contract for external reviews:** Responses coming back from an external review system no longer need to carry a type field. (v2.8-009) * **Off-platform review holds up:** Sending a case out to an external reviewer no longer returns a server error. (v2.8-010) * **Clear validation on missing type definitions:** A payload missing its type definition now returns a validation error that says so. * **Time remaining on every job:** The jobs list now shows time remaining instead of a dash. * **No repeated created date:** The duplicate Created On field has been removed from workflow details. * **Schedulers show their output schema:** The scheduler details page now displays the expected output. * **An accurate human task count:** The Human Tasks heading now counts the tasks actually listed. ### API * **Workflow API:** A first version of the public workflow API covers create, read, update and delete. * **Agent API per organization:** Agents can now be created and updated through the API, scoped to an organization. ### Optimize * **Faster, sharper workflow insights:** Workflow insights now run against a simplified representation of the workflow, which makes them quicker to produce and more accurate. * **A stronger default model:** The default AI model behind generation and chat has been upgraded. ### Govern * **API key labels tell the truth about expiry:** An API key that has passed its expiry date is now labelled as expired. (v2.8-011) * **A clearer invitation flow:** Inviting someone into an organization has been reworked end to end. (v2.8-012) * **Only the workspaces you belong to:** The workspaces list under your organization now shows just the workspaces you are part of. (v2.8-013) * **A guard rail on deleting an org unit:** Deleting an organization unit now asks for confirmation and warns you about anything that depends on it. * **One activity entry per invitation:** Accepting an org unit invitation is recorded once, not twice. * **Retagging is recorded where you look for it:** Moving resources to a new org unit is now logged in the destination unit's activity tab. * **Organization names follow one rule:** The characters allowed in an organization name are now the same on creation and on update, and Begin Analysis explains the rule instead of showing a generic error. * **A readable member roles drawer:** The member roles drawer header no longer overlaps the details beneath it when you scroll. ### Platform * **One clear limit on feedback:** The feedback field now enforces a single, clearly stated length limit. * **Feedback on a short screen:** The feedback dialog now fits shorter viewports. # v2.9 (Oct 13, 2026) Source: https://developer.opus.com/release-notes/opus-v2-9 Released 13 October 2026. Minor This release makes Opus easier to move around in and easier to hand off from. Global Search finds anything you can access across your organization, any discovered process can be exported as a standard BPMN file, and workflow activation now applies to a specific version, so the version you switched on stays the one that runs while you keep editing. The builder also picks up a round of quality-of-life work: a resizable Node Inspector, a searchable variable list, drag-to-reorder inputs and outputs, and images pasted straight into the agent chat. ### Discover * **Migrated processes show their latest state:** A process that was worked on in the earlier version of Discovery now opens with its most recent steps, details and approvals intact. (v2.9-001) * **Export a process as BPMN:** Download any process from the Canvas View export menu, alongside PNG and SVG, as a standard `.bpmn` file that opens in third-party BPMN tools. The export carries the flow and structure of the process: its steps, their order, decisions and parallel branches. * **Duration and Performed By explained:** The Duration and Performed By fields on a step now explain what they are for and how to use them, right where you see them. * **Faster replies in Discovery chat:** Opus Chat answers each turn of the process interview within seconds again, so the conversation keeps its pace. ### Build * **Activate a specific workflow version:** Activation now belongs to a workflow version. The version you activate stays live while you keep editing, instead of every autosave taking its place. * **Paste images into the agent chat:** Paste a screenshot straight from your clipboard into the agent chat instead of saving it and uploading it. Pasted images behave exactly like uploaded ones. * **A Node Inspector you can resize:** Drag the edge of the Node Inspector to widen it, or drag the dividers between Input, Settings and Output in the expanded view, so long code and payloads read line by line instead of wrapping. * **Search the Link Variable list:** The Link Variable dropdown now has a search bar, so you can find an upstream variable without scrolling through every node. * **Reorder input and output variables:** Drag input and output variables into the order you want. The new order is saved for everyone and keeps every value and link. * **Download Jira attachments:** A new Jira integration action downloads the attachments on a given ticket into your workflow. * **Choose any model and run:** Selecting a specific model on the Opus Agent node no longer holds up workflow execution. * **Copied workflows run their agents in any organization:** An agent node in a workflow copied into a different organization now runs just as it did in the original. * **Shared workflows hold up under load:** Large groups opening and duplicating the same shared workflow at once now each get a working copy straight away. * **Sub-workflows listed by name:** Sub-workflow cards show the workflow's name rather than its internal ID. * **Input and Output nodes stay in the chain:** Input and Output nodes load connected to the rest of the workflow every time you open the canvas. * **A tidy Generate Agent button:** The Generate Agent button sits clear of the prompt field and is only active when it can be used. * **Readable human task history:** A human task's version history shows what actually changed in each entry, with no duplicates. * **Accurate connection times on human tasks:** The Connected At time on a task's details page reflects when it actually connected. ### Run * **Room to read sub-workflow results:** Opening a sub-workflow from a case's execution timeline now shows its input and output in a full-page view, so payloads are no longer cut off at the edge of a side panel. * **Manual cases with PDF inputs:** Starting a manual case and attaching a PDF now previews the file and runs the case through to completion. ### Govern * **Notifications that say what happened:** In-app notifications for organization invitations, workspace invitations and role changes now say exactly what changed and take you to the page that matters: My Invitations, the workspace's About page or My Roles. * **Refreshed invitation emails:** The emails for organization, org unit, workspace and process collaboration invitations have been rewritten to be clearer. ### Platform * **Global Search:** Search across every resource you can access in your current organization and see results as you type, with the files you opened recently suggested before you start typing. * **One toast per action:** Confirmation toasts appear once, and collaborators invited to a process now see theirs. ### API * **Code API per organization:** Code can now be created and updated through the API, scoped to an organization. * **Connect integrations through the API:** New public endpoints connect an integration and return the IDs of active integration. # Custom Agent Source: https://developer.opus.com/tasks/agent/custom-agent Direct control over LLM selection, prompting, and output configuration for advanced AI tasks. The Custom Agent gives you direct access to frontier Large Language Models (LLMs) like GPT-5.2, Claude Opus 4.5, Gemini 3, and Deepseek V3. Pick your model, write your prompts, and get a single text response—perfect for simple, one-shot AI tasks. ## Key Capabilities Pick from GPT-5.2, Claude Opus 4.5, Gemini 3, Deepseek V3, and other frontier LLMs. Use a **System Prompt** for context and role, plus a **Prompt** for your specific instruction. Lower temperature for consistent, focused outputs. Higher for more creative responses. Returns a single **Agent Response** field with the model's text output. ## Configuration ### Central Panel Options | Setting | Description | | - | - | | **Model** | Choose your LLM (GPT-5.2, Claude Opus 4.5, Gemini 3, Deepseek V3, etc.) | | **Prompt** | Your main instruction—what you want the AI to do | | **System Prompt** | Context and role for the model (e.g., "You are a data extraction assistant") | | **Temperature** | Controls randomness: 0 = focused and consistent, 1 = creative and varied | ### Input Variables Custom Agent accepts all typed variables: | Type | Best Practice | | - | - | | **Text** | Primary input type; most reliable | | **Number** | Convert to string in prompt if needed | | **Object/List** | Serialize as JSON string for reliable handling | For file inputs, use a Text Extraction task first to convert the file to text before passing to Custom Agent. ### Output Variables Custom Agent returns a single output called **Agent Response**, which contains the text generated by the LLM. Unlike Opus Agent, Custom Agent always returns one text output. If you need multiple structured outputs: * use Opus Agent, or * parse the Custom Agent's response in a downstream Opus Agent. ## Using Custom Agent Drag a Custom Agent task into the Builder. Choose your preferred LLM from the Model dropdown based on your requirements (capability, cost, latency). Define the agent's persona and behavior. Include explicit format instructions for structured outputs. ``` You are a data extraction assistant. Always return valid JSON matching the provided schema. Do not include prose or explanations outside the JSON structure. ``` Write the task-specific instructions. Reference input variables using the templating syntax. Use lower temperature (0) for consistent, deterministic outputs. Use higher temperature (closer to 1) for creative tasks. Configure the output variable type. Preview with representative data to verify the output format. ## Prompt Engineering For Reliability The power of Custom Agent comes from precise prompt design. Follow these patterns for consistent results: ### Enforce Structured Output ``` System Prompt: You are a structured data extractor. Your responses must be valid JSON matching this exact schema: { "field1": "string", "field2": number, "field3": ["array", "of", "strings"] } Do not include any text outside the JSON. Do not include markdown code fences. Return only the raw JSON object. ``` ### Maintain Consistency ``` System Prompt: Always format dates as YYYY-MM-DD. Always format currency as numbers without symbols (e.g., 1000.50). Always use lowercase for category names. ``` ## Best Practices Use Opus Text Extraction to extract text from files before passing to Custom Agent. Include schema definitions directly in prompts: * "Return only valid JSON matching this schema: `{...}`" * "Do not include prose or markdown" * "Use null for missing fields, not empty strings" For structured extraction and deterministic tasks: * Set temperature to 0 or near-0 * Higher temperatures introduce variation * Reserve higher temperatures for creative tasks only ## Related Resources Simplified AI tasks with auto-generated blueprints. AI-powered validation and repair for outputs. Deterministic Python logic for type validation. Learn workflow design fundamentals. # Decision Agent Source: https://developer.opus.com/tasks/agent/decision-agent Automatically route your workflow down different paths based on conditions you define. The Decision Agent lets your workflow make decisions automatically. You set up a condition (like "is variable `{amount}` over \$1000?"), and the workflow takes one path if it's true, and another if it's false. ## Key Capabilities Build conditions using logical operators—no coding required. Or just describe your condition in plain English. Compare dates, numbers, text, and yes/no values with the right operators. Outputs True or False to send your workflow down different paths. ## Two Ways to Set Conditions Each condition can be either a logical expression or natural language. You can add multiple conditions and combine them with AND or OR. Build your condition by selecting three things: | Field | What It Does | | - | - | | **Source** | The variable you want to check | | **Operation** | How to compare it (see options below) | | **Value** | The reference value to compare against | **Available operations:** * Equals / Not Equals * Contains / Not Contains * Starts With / Ends With * Is Empty / Is Not Empty * Is Null / Is Not Null **Best for:** * Important decisions that need to be auditable * Precise conditions that must work the same way every time Toggle on "Natural Language" and describe your condition in plain English. **Examples:** * "If the amount is greater than 10000" * "If the risk score indicates high risk" * "If the document contains sensitive keywords" **Best for:** * Quick prototyping * Simple conditions For important decisions, use Logical Expression instead. Natural language can sometimes be interpreted differently than you expect. ## Output The Decision Agent produces these outputs: | Output | What It Contains | | - | - | | **Final Decision** | True or False—the combined result of all your conditions | | **Condition 1, 2, etc.** | True or False for each individual condition | Make sure you connect both the True and False paths to something. If you leave one unconnected, your workflow might not work correctly. ## How to Add a Decision Agent Drag a Decision Agent into your workflow. Pick Logical Expression or Natural Language. Set up what you want to check—like "amount greater than 1000" or "status equals approved". Wire the True output to one path and the False output to another. Make sure both are connected. Run a preview with test data to make sure both paths work as expected. ## Tips for Better Results Rule Builder gives you: * Clear logic you can audit later * Consistent behavior every time * Easier troubleshooting when something goes wrong If you leave the True or False path unconnected: * Your workflow might get stuck * You might get unexpected results * Even if one path doesn't need to do anything, connect it to something In preview mode, run tests that trigger both True and False: * Make sure the True path does what you expect * Make sure the False path does what you expect * Check that the right data flows to the next steps ## Common Use Cases ### High-Value Items Send big transactions to manual review: ``` Condition: amount > 10000 True → Manual review False → Process automatically ``` ### Status Checks Take different actions based on approval status: ``` Condition: status equals "approved" True → Proceed to fulfillment False → Send rejection notice ``` ### Overdue Items Flag items that missed their deadline: ``` Condition: deadline before today True → Mark overdue, escalate False → Continue normally ``` ### Risk Levels Route risky items to the right team: ``` Condition: risk_level equals "high" True → Send to compliance False → Standard processing ``` ## Related Let a person make the decision instead of automated rules. Have AI review and auto-correct outputs. Learn how all the pieces fit together. Master the workflow design environment. # Human Decision Agent Source: https://developer.opus.com/tasks/agent/human-decision-agent Pause your workflow for a person to make a routing decision when human judgment is needed. The Human Decision Agent works just like the [Decision Agent](/tasks/agent/decision-agent), but instead of the system evaluating conditions automatically, a real person reviews the situation and decides which path to take. You set a deadline so the person has time to make their decision, then the workflow continues based on their choice. ## Key Capabilities Pause your workflow for a real person to make critical decisions. Give people a specific timeframe to complete their decision. Set up decisions using logical rules or natural language. Outputs True or False to send your workflow down different paths. ## When to Use It Use Human Decision Agent when you need a person to make the routing decision instead of automated rules. Common examples: * A compliance officer needs to approve before proceeding * Someone needs to judge whether output meets quality standards * A manager needs to decide how to handle an edge case **Human Decision Agent vs Decision Agent:** The Decision Agent runs automatically and finishes in real-time. The Human Decision Agent pauses for a person to decide, so you set a deadline to give them time to respond. ## Two Ways to Set Conditions Each condition can be either a logical expression or natural language. You can add multiple conditions and combine them with AND or OR. Build your condition by selecting three things: | Field | What It Does | | - | - | | **Source** | The variable you want to check | | **Operation** | How to compare it (see options below) | | **Value** | The reference value to compare against | **Available operations:** * Equals / Not Equals * Contains / Not Contains * Starts With / Ends With * Is Empty / Is Not Empty * Is Null / Is Not Null **Best for:** * Important decisions that need to be auditable * Precise conditions that must work the same way every time Toggle on "Natural Language" and describe your condition in plain English. **Examples:** * "If the amount is greater than 10000" * "If the risk score indicates high risk" * "If the document contains sensitive keywords" **Best for:** * Quick prototyping * Simple conditions For important decisions, use Logical Expression instead. Natural language can sometimes be interpreted differently than you expect. ## Output The Human Decision Agent produces these outputs: | Output | What It Contains | | - | - | | **Final Decision** | True or False—the combined result of all your conditions | | **Condition 1, 2, etc.** | True or False for each individual condition | Make sure you connect both the True and False paths to something. If you leave one unconnected, your workflow might not work correctly. ## How to Add a Human Decision Agent Drag a Human Decision Agent into your workflow. Pick Logical Expression or Natural Language. Set up what you want the person to evaluate—like "amount greater than 1000" or "status equals approved". Choose how many hours the person has to make their decision. Wire the True output to one path and the False output to another. Make sure both are connected. Run a preview with test data to make sure both paths work as expected. ## Tips for Better Results Logical Expression gives you: * Clear logic you can audit later * Consistent behavior every time * Easier troubleshooting when something goes wrong If you leave the True or False path unconnected: * Your workflow might get stuck * You might get unexpected results * Even if one path doesn't need to do anything, connect it to something Be realistic about deadlines: * Remember people work in different time zones * Harder decisions need more time * Build in some buffer for busy days People need to understand what they're deciding: * Explain what to look for * Give examples of when to choose True vs False * Include any thresholds or standards to apply ## Related Have the system make decisions automatically instead of a person. For simple approve/reject decisions—no routing needed. Collect information from a person instead of routing decisions. Learn how all the pieces fit together. # Opus Agent Source: https://developer.opus.com/tasks/agent/opus-agent The default AI workhorse for LLM-based reasoning, extraction, and generation with typed inputs and outputs. The Opus Agent is your go-to tool for AI-powered automation. Describe what you want in plain English, and it generates a step-by-step blueprint to accomplish the task. You can refine the blueprint, adjust the steps, or convert it to code for full control. ## Key Capabilities Describe what you want to do, and Opus generates a step-by-step blueprint with the inputs and outputs it needs. Edit the generated steps, add new ones, remove what you don't need, or regenerate with updated instructions. The Builder automatically connects outputs from previous tasks to inputs by matching names and types. Convert any blueprint to Python code for full control while keeping the same inputs and outputs. ## How The Blueprint Works When you describe your task in the central description field, Opus Agent generates a blueprint—a series of **Required Steps** that break down your request into smaller actions. Each step has: * **Objective**: What the step aims to accomplish * **Description**: How the step will be carried out After generation, you can: * **Edit steps** manually to fine-tune the logic * **Add new steps** if something is missing * **Delete steps** you don't need * **Regenerate** by adding more instructions and clicking Generate again The blueprint also auto-generates the Input and Output variables based on what your task needs. You can always adjust these manually. ## Operating Modes Opus Agent offers two modes: The fastest way to get started with AI tasks. **How it works:** 1. Describe your goal in natural language 2. The system generates a multi-step blueprint 3. Input and output variables are auto-inferred 4. Tweak the blueprint as many times as you need—your inputs and outputs stay intact based on your described task **Best for:** * Content generation * Data extraction * Summarization and classification * Reliable processing that behaves as expected, even at enterprise scale Accomplish the blueprint's tasks by writing and running code. **How it works:** 1. Start with a blueprint (same as Lite mode) 2. Switch to Advanced mode 3. Click **Build** to generate the code from your blueprint 4. Run the task using the built code **Best for:** * Custom logic not expressible in blueprints * Fine-grained control over execution * Deterministic post-processing * Advanced users who want full flexibility ## Using Opus Agent Click the **+** button or drag an Opus Agent task into the Builder. In the central description field, write what you want the task to do. For example: *"Extract the customer name, invoice date, and total amount from the document."* Click **Generate**. Opus creates a blueprint with Required Steps, each having an Objective and Description. It also auto-generates the Input and Output variables. Review the steps. Edit, add, or delete them as needed. You can also add more instructions and click **Generate** again to update the blueprint. Use **Auto Link** to automatically connect inputs to matching outputs from previous tasks. You can also link them manually. Run a preview with sample data to make sure outputs look right before activating the workflow. ## Best Practices Define your input and output variable types at the start of your design. * Finalize output structures before building downstream logic * Regenerate the blueprint if IO changes materially * Test with representative data in preview mode When downstream logic will branch or serialize data, use JSON mapped to Object variables: * Explicit schemas reduce parsing errors * Structured outputs are easier to validate * Type discipline improves workflow reliability Always preview tasks with representative data before activation: * Check that output types render as expected * Verify variable mappings are correct * Test edge cases (empty inputs, long content) The **Switch to Advanced** button converts your blueprint into an Advanced Task: 1. Click **Switch to Advanced** 2. Click **Build** to generate the full code from your blueprint 3. Run the task using the built code This gives you full control while preserving your inputs and outputs. ## Common Use Cases ### Document Summarization Extract key points from lengthy documents: ``` Input: document_text (Text) Output: summary (Text), key_points (List) Prompt: "Summarize the following document, extracting the main thesis and up to 5 key points. Return as structured JSON." ``` ### Data Extraction Pull structured fields from unstructured text: ``` Input: raw_text (Text) Output: extracted_data (Object) Prompt: "Extract the following fields from the text: name, date, amount, category. Return as JSON matching the output schema exactly." ``` ### Classification Categorize content into predefined buckets: ``` Input: content (Text), categories (List) Output: classification (Text), confidence (Number) Prompt: "Classify the content into one of the provided categories. Return the category name and a confidence score between 0 and 1." ``` ## Related Resources Direct control over LLM selection and prompting. AI-powered review to validate and repair outputs. Custom Python logic for deterministic transformations. Learn workflow design fundamentals. # Opus Code Source: https://developer.opus.com/tasks/agent/opus-code Write custom Python code when you need logic that other tasks can't handle. Opus Code lets you write Python code directly in your workflow. Use it when you need custom logic or data transformations that other tasks can't handle. Your code runs in a secure environment with access to data from earlier steps in your workflow. ## Key Capabilities Write and run Python code in a secure environment. Read data from earlier steps and pass results to later steps. Do calculations, transformations, validations—anything you can code. Connect to services not supported by integrations or External Service. ## When to Use It Use Opus Code when you need to do something that other tasks can't handle. Common examples: * Transform data into a different format * Calculate values or run business logic * Clean up messy data before using it * Call an API that isn't supported by the Integration Marketplace or [External Service](/tasks/data/external-service) task * Validate that data matches what you expect Keep your code simple and focused. If you need to do multiple things, use multiple Opus Code tasks instead of a big one—it's easier to debug. ## Reading and Writing Data Your code can read data from earlier steps and pass results to later steps using a special syntax: ```python theme={null} # Read an input variable my_value = {{ input_variable_name }} # Write to an output variable {{ output_variable_name }} = my_value ``` **Input variables** are read-only—you can read them but not change them. **Output variables** send data out from your code to later steps. ## Working with Files Inside an Opus Code task, an `Opus` object is pre-defined and ready to use—no import needed. Use it to work with files in Opus storage: download an existing file, create a new one, and upload results back to storage so later steps can use them. All file operations live under `Opus.file`: * `Opus.file.download(url)` — fetch a file from Opus storage by URL, returning an `OpusFile` you can read and modify locally. * `Opus.file.create(name, type)` — create a new empty `OpusFile` of a given type (for example `"CSV"` or `"PDF"`). * `Opus.file.upload(file)` — upload an `OpusFile` back to storage and get a new file URL. `Opus.file.presigned_download(url)` (for a temporary download link) and the read/write methods on the returned `OpusFile` (such as `read_text`, `write_text`, `read_bytes`, `write_bytes`, and `open`) round out the API. ```python theme={null} # Download a CSV, modify it, and upload the result file = Opus.file.download("https://files.opus.com/reports/data.csv") original = file.read_text() modified = original.replace("old_value", "new_value") file.write_text(modified) new_url = Opus.file.upload(file) ``` Downloaded files are modified locally only. Changes aren't saved back to Opus storage until you call `Opus.file.upload`, which creates a new file and returns a new URL—the original remote file is never modified. See the [Opus SDK](/opus-sdk/overview) for the full file API (including the `OpusFile` interface and error handling), and [Working with File Formats](/opus-sdk/file-formats) for per-format recipes covering CSV, XLSX, PDF, DOCX, and more. ## Supported Packages Opus Code comes with these Python packages pre-installed. See [Available Packages](/opus-sdk/available-packages) for the complete, up-to-date list. | Category | Packages | | - | - | | **Data** | json, csv, collections, dataclasses, enum, copy | | **Text** | re, string, html | | **Math** | math, statistics, random, decimal, fractions | | **Time** | datetime, time, python-dateutil | | **Utilities** | itertools, functools, typing, uuid | | **Encoding** | hashlib, base64 | | **Markup & Archives** | xml, zipfile | | **Advanced** | abc, warnings, contextlib, concurrent, concurrent.futures | | **HTTP** | requests | | **Office Documents** | openpyxl, python-docx, python-pptx | | **PDF** | PyPDF2, pdfplumber, pymupdf, reportlab, fpdf2, pdf2docx, pdf2image | | **Images** | pillow, opencv-python-headless | | **Other** | python-magic, toon-format | ## How to Add Opus Code Drag an Opus Code task into your workflow. Add input variables and connect them to data from earlier steps. Write your Python code in the editor. Read inputs and assign values to outputs. Add output variables that later steps can use. Run a preview to make sure your code works with real data. ## Tips for Better Results One task, one job: * Do one focused thing per Opus Code task * Use multiple small tasks instead of one big one * Easier to debug when something goes wrong Validate data at the start of your code: * Make sure required fields exist * Check that data is the type you expect * Handle empty or missing data gracefully Plan for things going wrong: * Use try/except to catch errors * Set an error output so later steps know something failed * Write clear error messages Before activating your workflow: * Run preview with realistic test data * Check that outputs look correct * Try edge cases to make sure your code handles them ## Related Work with files in Opus storage using the pre-defined `Opus` object. Per-format recipes for CSV, XLSX, PDF, DOCX, and more. Browse the full list of Python packages you can import. Call external APIs without writing code. Use AI to handle tasks instead of writing code. Get structured outputs from an LLM. Learn how all the pieces fit together. Design, configure, and test your workflow in the visual editor. # Opus Human Task Source: https://developer.opus.com/tasks/agent/opus-human-task Pause your automation to collect information from a real person when you need human input to continue. Sometimes your automation hits a point where it needs a real person to step in—maybe to fill in missing information or information that can only be reliably filled in by a person. That's what Opus Human Task is for. it pauses your process till the human completes their assigned task, and then the workflow proceeds as usual. ## When to Use It | Situation | Real-World Example | | - | - | | **AI needs help** | The AI extracted most of the data, but needs a person to fill in a field it couldn't figure out | | **Collecting info** | You need someone to enter data that isn't available anywhere else | Need someone to just approve or reject something? Use [Human Review](/tasks/review/human-review) instead. Opus Human Task is for when you need people to perform a full-fledged task. ## Setting It Up ### Basic Settings | Setting | What It Means | | - | - | | **Input** | Variables from earlier in the workflow that the person can see while completing the task | | **Task Guidance** | Instructions explaining what the person needs to do | | **Deadline (In Hours)** | How long the person has to complete the task | | **Output** | Variables the workflow designer defines that the person must fill in when completing the task | ## How to Add an Opus Human Task Drag an Opus Human Task from the sidebar into your workflow. Connect variables from earlier steps that the person will need to see while completing the task. Explain what the person needs to do. Be specific—the clearer your instructions, the better the results. Choose how many hours the person has to complete the task. Add the variables that the person must fill in when completing the task. ## Tips for Better Results Don't assume people know the context. Tell them: * Why you need this information * Where they can find it * What format you expect (e.g., "Enter the date as MM/DD/YYYY") The easier the task, the faster people complete it: * Only ask for what you actually need * Fill in fields automatically when you can * Keep instructions short but helpful Be realistic about deadlines: * Remember people work in different time zones * Harder tasks need more time * Build in some buffer for busy days * Only use tight deadlines when it's truly urgent Before you turn it on for real: * Try completing the task yourself in preview mode * Make sure all the fields work right * Check that your instructions make sense * Verify the data goes where it should afterward ## Related For simple approve/reject decisions—no form needed. Let a person choose which path your workflow takes next. Have AI do the reviewing instead of a person. Learn how all the pieces fit together. # Export Data Source: https://developer.opus.com/tasks/data/export-data Send files and data from your workflow to external services. The Export Data task sends files and data from your workflow to external services. It comes with built-in support for common cloud services and enterprise systems—just pick your destination and connect. **Deprecation Notice:** Export Data is being deprecated soon. Please use the [Integrations Task](/tasks/data/integrations) instead, which allows you to connect to 3,500+ integrations from the [Integrations Marketplace](/integrations/overview). ## Key Capabilities Native support for Google Sheets, S3, Slack, enterprise systems, and more—easy to set up. Use shared or personal credentials to connect securely. ## When to Use It Use Export Data when you need to send files or data from your workflow to an external service: * Push processed documents to Google Sheets * Send notifications to Slack or Email * Upload files to AWS S3 * Connect to enterprise systems like SAP, Workday, or Epic ## Supported Data Destinations These data destinations have built-in support with easy setup: ### Standard | Destination | Description | | - | - | | **AWS S3** | Upload files to S3 buckets | | **Email** | Send email messages | | **Gmail** | Send emails via Gmail | | **Google BigQuery** | Push data to BigQuery datasets | | **Google Sheets** | Write data to spreadsheets | | **Slack** | Send messages to channels | | **Zapier** | Trigger Zapier automations | ### Enterprise These destinations require an Enterprise plan: | Destination | Description | | - | - | | **BlackRock - Aladdin** | Investment management platform | | **Bloomberg - AIM** | Asset and investment management | | **Cerner - Cerner Millennium** | Healthcare EHR system | | **Epic Systems - Epic EHR** | Healthcare EHR system | | **Finacle - Infosys** | Core banking solution | | **Finastra Fusion Essence / Equation** | Banking and financial services | | **FIS - InvestOne** | Investment accounting | | **FIS Profile / IBS - FIS Global** | Banking platform | | **Flexcube - Oracle Financial Services** | Core banking solution | | **GE Healthcare - Centricity PACS/RIS** | Medical imaging systems | | **MasterControl - Quality Excellence** | Quality management system | | **Meditech - Expanse EHR** | Healthcare EHR system | | **Oracle - Argus Safety** | Pharmacovigilance and drug safety | | **SAP - SAP S/4HANA** | Enterprise resource planning | | **SimCorp - SimCorp Dimension** | Investment management | | **Sunquest - Laboratory Information System** | Lab information management | | **T24 Transact - Temenos** | Core banking platform | | **Veeva Systems - Vault LIMS** | Lab information management | | **Veeva Systems - Vault QMS** | Quality management system | | **Workday** | HR and financial management | ## How to Add Export Data Drag an Export Data task into your workflow where you need to send data externally. Select from the supported data destinations for easy setup, or search the Integration Marketplace for other services. Pick what you want to do—like "Send Message", "Create Row", or "Upload File". Select existing credentials or connect a new account. Fill in the details the integration needs—like a channel ID, file path, or spreadsheet name. You can use variables from earlier tasks. Run a preview to make sure the export works correctly. ## Tips for Better Results Make sure the account you're using has permission to write to the destination you're targeting. Before activating your workflow, run a preview to verify: * The credentials work * The destination path or ID is correct * The data exports as expected Sometimes destinations become unavailable or permissions change. Consider adding a Decision Agent after your export to check if it succeeded before continuing. ## Related Pull data from external services into your workflow. Connect to custom APIs not in the supported destinations or marketplace. Explore all available integrations. Learn how all the pieces fit together. # External Service Source: https://developer.opus.com/tasks/data/external-service Connect to any REST API. The External Service task lets you connect your workflow to any REST API. You configure the endpoint, authentication, and request details—then map the response to use in later tasks. For common services like Google Drive, Slack, or AWS S3, use the [Integrations Task](/tasks/data/integrations) instead—it connects to 3,500+ services from the [Integrations Marketplace](/integrations/overview) and is simpler to set up. ## Key Capabilities Connect to any HTTP endpoint, public or private. Support for Bearer tokens, API keys, Basic auth, JWT, or no auth. Configure HTTP method, headers, and request body. Returns request details and service response for downstream processing. ## When to Use It Use External Service when you need to call a custom API: * Connect to proprietary internal APIs * Access public APIs without built-in integrations * Send data to webhook endpoints * Fetch data from specialized services ## The 5 Configuration Areas To call an API, you'll configure these five things: | Area | What It Does | | - | - | | **Authentication** | How to authenticate: Bearer token, API key, Basic auth, JWT, or none | | **Endpoint URL** | The full URL of the API you're calling | | **HTTP Method** | The action: GET (fetch data), POST (send data), PUT, DELETE, PATCH | | **Content Type** | Format of your request (usually `application/json`) | | **Request Body** | The data to send (for POST, PUT, PATCH requests) | ### Authentication Options | Type | Use Case | | - | - | | **None** | Public APIs that don't require authentication | | **Bearer Token** | APIs using OAuth2 or API tokens | | **API Key (Header)** | APIs that accept keys in custom headers | | **Basic Auth** | APIs using username/password authentication | | **JWT** | APIs requiring signed JSON Web Tokens | ### Output The External Service task always returns two output variables: | Output | Type | Description | | - | - | - | | **Request Details** | Object | Contains information about the request that was made | | **Service Response** | Text | The raw response from the API | To parse or extract specific fields from the Service Response, add an [Opus Agent](/tasks/agent/opus-agent) task after External Service to process and structure the data. ## How to Add External Service Drag an External Service task into your workflow where you need to call an API. Type the full API URL and select the HTTP method (GET, POST, etc.). Choose the authentication type and provide credentials if needed. For public APIs, select "None". Add any required headers and configure the request body. Run a preview to verify the API call works and returns the expected response. Add an Opus Agent task after External Service to extract specific fields from the Service Response. ## Tips for Better Results Before configuring External Service: * Test the API with a tool like Postman or curl * Verify your credentials work * Understand the response structure APIs can fail for various reasons: * Check the response for success/failure status * Use a Decision Agent to handle error responses * Add fallback paths for when calls fail Protect your API credentials: * Use organization-scoped credentials for shared APIs * Never hardcode secrets in request bodies * Use variables for sensitive values ## Related Pull data from services in the Integration Marketplace. Send data to services in the Integration Marketplace. Write custom code for complex API logic. Explore all available integrations. # Import Data Source: https://developer.opus.com/tasks/data/import-data Pull files and data from external services into your workflow. The Import Data task pulls files and data from external services into your workflow. It comes with built-in support for common cloud services and enterprise systems—just pick your source and connect. **Deprecation Notice:** Import Data is being deprecated soon. Please use the [Integrations Task](/tasks/data/integrations) instead, which allows you to connect to 3,500+ integrations from the [Integrations Marketplace](/integrations/overview). ## Key Capabilities Native support for Google Drive, S3, enterprise systems, and more—easy to set up. Use shared or personal credentials to connect securely. ## When to Use It Use Import Data when you need to pull files or data into your workflow from an external service: * Import documents from Google Drive for AI processing * Pull data from Google Sheets or BigQuery * Fetch files from AWS S3 * Connect to enterprise systems like SAP, Workday, or Epic ## Supported Data Sources These data sources have built-in support with easy setup: ### Standard | Source | Description | | - | - | | **AWS S3** | Import files from S3 buckets | | **Google BigQuery** | Pull data from BigQuery datasets | | **Google Calendar** | Fetch calendar events and schedules | | **Google Drive** | Import documents, spreadsheets, and files | | **Google Places** | Get location and business data | | **Google Search** | Retrieve search results | | **Google Sheets** | Pull spreadsheet data | | **Google Translate** | Access translation services | | **PDF Generator API** | Work with PDF generation | | **X (Formerly Twitter)** | Import social media data | ### Enterprise These sources require an Enterprise plan: | Source | Description | | - | - | | **BlackRock - Aladdin** | Investment management platform | | **Bloomberg - AIM** | Asset and investment management | | **Cerner - Cerner Millennium** | Healthcare EHR system | | **Epic Systems - Epic EHR** | Healthcare EHR system | | **Finacle - Infosys** | Core banking solution | | **Finastra Fusion Essence / Equation** | Banking and financial services | | **FIS - InvestOne** | Investment accounting | | **FIS Profile / IBS - FIS Global** | Banking platform | | **Flexcube - Oracle Financial Services** | Core banking solution | | **GE Healthcare - Centricity PACS/RIS** | Medical imaging systems | | **LSEG World-Check** | Risk intelligence and screening | | **MasterControl - Quality Excellence** | Quality management system | | **Meditech - Expanse EHR** | Healthcare EHR system | | **Oracle - Argus Safety** | Pharmacovigilance and drug safety | | **SAP - SAP S/4HANA** | Enterprise resource planning | | **SimCorp - SimCorp Dimension** | Investment management | | **Sunquest - Laboratory Information System** | Lab information management | | **T24 Transact - Temenos** | Core banking platform | | **Veeva Systems - Vault LIMS** | Lab information management | | **Veeva Systems - Vault QMS** | Quality management system | | **Workday** | HR and financial management | ## How to Add Import Data Drag an Import Data task into your workflow where you need to pull external data. Select from the supported data sources for easy setup, or search the Integration Marketplace for other services. Pick what you want to do—like "Get File", "Download from Path", or "Read Spreadsheet". Select existing credentials or connect a new account. Fill in the details the integration needs—like a file path, folder ID, or other settings. You can use variables from earlier tasks. Run a preview to make sure the import works correctly. ## Tips for Better Results Make sure the account you're using has permission to access the file or data you're trying to import. Before activating your workflow, run a preview to verify: * The credentials work * The file path or ID is correct * The imported data looks right Sometimes files get moved or deleted in the external services database. Consider adding a Decision Agent after your import to check if it succeeded before continuing. ## Related Send data from your workflow to external services. Connect to custom APIs not in the supported sources or marketplace. Explore all available integrations. Learn how all the pieces fit together. # Integrations Task Source: https://developer.opus.com/tasks/data/integrations Use pre-configured integrations from the marketplace in your workflows. The Integrations task lets you use external services in your workflow. First, configure your integrations in the [Integrations Marketplace](/integrations/overview)—then they become available to use in your workflows through this task. Before using the Integrations task, you must first set up your integrations in the [Integrations Marketplace](/integrations/overview). Once configured there, they'll appear as options when you add an Integrations task to your workflow. ## Key Capabilities Use integrations you've already set up in the Integrations Marketplace. Choose from a comprehensive library of pre-built actions for each integration. Credentials are managed in the marketplace and securely reused in workflows. Import data into your workflow or export results to external services. ## How It Works Go to the [Integrations Marketplace](/integrations/overview) from the left navigation. Search for the service you need, connect your credentials, and configure the integration. In the Builder, drag an Integrations task into your workflow where you need to connect to an external service. Choose from the integrations you've already set up in the marketplace. Only configured integrations will appear as options. Pick what you want to do—like "Get File", "Send Message", "Create Row", or "Upload File". Fill in the details the action needs—like a file path, channel ID, or spreadsheet name. You can use variables from earlier tasks. Run a preview to make sure the integration works correctly. ## When to Use It Use the Integrations task when you need to connect your workflow to an external service: * Pull documents from Google Drive for AI processing * Push results to Google Sheets or databases * Send notifications to Slack or Email * Fetch or upload files to AWS S3 * Connect to enterprise systems like SAP, Workday, or Epic ## Tips for Better Results Configure all the integrations you need in the [Integrations Marketplace](/integrations/overview) before you start building your workflow. This makes it easier to select them when adding Integrations tasks. Before activating your workflow, run a preview to verify: * The credentials work * The file path or ID is correct * The data flows as expected Sometimes external services become unavailable or permissions change. Consider adding a Decision Agent after your integration to check if it succeeded before continuing. ## Related Configure integrations before using them in workflows. Connect to custom APIs not available in the marketplace. Learn how all the pieces fit together. Process imported data with AI reasoning. # Opus Text Extraction Source: https://developer.opus.com/tasks/data/opus-text-extraction Extract text from documents and images so your workflow can process them. The Opus Text Extraction task uses OCR (Optical Character Recognition) to pull text out of documents and images. Feed it a PDF, PNG, or JPEG, and it returns the text content—ready for processing by Opus Agent, Custom Agent, or other tasks in your workflow. ## Key Capabilities Extract text from scanned documents and images. Works with PDF, PNG, JPEG, and JPG files. For multi-page documents, get text from each page separately. Output flows directly to AI tasks for analysis. ## When to Use It Use Opus Text Extraction when you need to convert documents or images into text your workflow can process: * Pull text from scanned invoices or receipts * Extract text from screenshots or photos * Convert PDFs into text for AI analysis * Digitize paper documents for processing Opus Text Extraction outputs raw text. To extract specific fields (like amounts from invoices), follow it with an Opus Agent task to parse and structure the text. ## Supported File Types | Format | Extensions | | - | - | | **PDF** | `.pdf` | | **PNG** | `.png` | | **JPEG** | `.jpeg`, `.jpg` | Only PDF, PNG, JPEG, and JPG formats are supported. Other file types will cause the task to fail. The maximum file size is **10 MB**. ## Input The **File** input accepts the document to extract text from. Only File (single) type is supported; multiple files are not currently supported. ## Synchronous Extraction The **Synchronous Extraction** toggle (off by default) controls how the extraction is processed: * **Off (Asynchronous):** Supports multi-page PDFs. The extraction runs in the background and retrieves results when complete. Use this for documents with multiple pages or when processing larger files. * **On (Synchronous):** Returns results immediately in real-time. However, this mode only supports single-page documents. If you pass a multi-page PDF with synchronous extraction enabled, the extraction will fail. For documents with varying page counts, keep synchronous extraction off to ensure reliable processing. ## How to Add Opus Text Extraction Drag an Opus Text Extraction task into your workflow where you need to convert documents to text. Link the file input to a source—like a Workflow Input, Import Data task, or another task's file output. Give the extracted text output a meaningful name so you can reference it in later tasks. Wire the text output to tasks that will process the content—like Opus Agent or Custom Agent. Run a preview with a sample document to verify the extraction works correctly. For multi-page PDFs, the output is a list where each item contains the text from one page. This makes it easier to process documents page by page. ## Tips for Better Results OCR accuracy depends on input quality: * Use high-resolution scans (300 DPI or higher) * Make sure documents are properly aligned * Avoid blurry or distorted images * Ensure good contrast between text and background OCR isn't perfect—plan for errors: * Use Agentic Review to check extraction quality * Add Human Review for critical documents * Handle low-confidence extractions appropriately Opus Text Extraction outputs raw text: * Use Opus Agent to parse into structured fields * Use Custom Agent to extract specific data points * Validate structure before further processing ## Related Process extracted text with AI reasoning. Parse extracted text into structured data. Pull documents from connected services. Validate extraction quality with human or AI review. # Execute Workflow Source: https://developer.opus.com/tasks/execute-workflow Run another workflow inside your workflow to reuse logic and keep things organized. The Execute Workflow task lets you run another workflow (called a sub-workflow) inside your main workflow. Use it to break complex automations into smaller, reusable pieces that are easier to build, test, and maintain. ## Key Capabilities Build once, use in multiple workflows. Send data to the sub-workflow and get results back. Sub-workflows run on their own, making them easier to test and debug. Keep complex workflows manageable by splitting them into parts. ## When to Use It Use Execute Workflow when you want to: * Reuse the same logic across multiple workflows * Break a complex workflow into smaller, manageable pieces * Let different team members work on different parts * Test pieces of your automation independently Execute Workflow is for running a separate workflow inside your workflow. For simple yes/no routing within a single workflow, use [Decision Agent](/tasks/agent/decision-agent) instead. ## Requirements Before you can use a workflow as a sub-workflow, it must meet these requirements: | Requirement | Why | | - | - | | **Must be activated** | Only active workflows can be called as sub-workflows | | **Same workspace** | The sub-workflow must be in the same workspace as the parent | | **No human tasks** | Sub-workflows can't contain Human Review, Human Decision Agent, or Opus Human Task—they run automatically without waiting for people | | **Has inputs and outputs defined** | The sub-workflow needs Workflow Input and Workflow Output tasks so data can flow in and out | ## How to Add Execute Workflow Build the workflow you want to reuse: * Add a Workflow Input task with the data it needs * Add your processing logic * Add a Workflow Output task with the results to return * Make sure there are no human tasks Test it thoroughly in preview mode, then activate it. Sub-workflows must be active before they can be called. Drag an Execute Workflow task into your main workflow where you need to call the sub-workflow. Choose the sub-workflow from the dropdown. Only **active** workflows in the **same workspace** that **don't contain human tasks** (Human Review, Human Decision Agent, or Opus Human Task) will appear. **Need human reviews, tasks, or decisions?** Put them in the parent workflow, not the sub-workflow. Let the sub-workflow do its processing, then review the outputs after it finishes. **Avoid loops:** Make sure the sub-workflow doesn't call back to the parent workflow (directly or through other workflows). This creates an infinite loop that will never finish. Opus has built-in guardrails to detect and prevent this. The sub-workflow's inputs are automatically shown. Connect variables from your parent workflow to each input. The inputs and outputs come from the sub-workflow itself. To change them, edit the sub-workflow directly. The sub-workflow's outputs become available in your parent workflow. Connect them to later tasks. Run a preview to make sure data flows correctly between the parent and sub-workflow. ## Tips for Better Results Each sub-workflow should do one thing well: * Easier to test and debug * More reusable across different workflows * Simpler to understand and maintain Before using a sub-workflow in a parent: * Run it with test data in preview mode * Check that outputs are correct * Make sure it handles edge cases Avoid sub-workflows that call sub-workflows that call sub-workflows: * Hard to debug when something goes wrong * Increases total run time * Keep it to 2-3 levels maximum Design sub-workflows to return useful information when things go wrong: * Include a status output (success/failure) * Return error details so the parent can decide what to do ## Related Learn how workflows work. Master the workflow design environment. Route your workflow based on conditions. Write custom code for simple transformations. # Off-Platform Review Source: https://developer.opus.com/tasks/off-platform-review Send an earlier step's output to your own application for a person to review, and resume the workflow with their decision. The Off-Platform Review task sends an earlier step's output to a system you run, so a person can review it in your application instead of in Opus. Opus posts the step's full execution context to your webhook and pauses the workflow. Your reviewer looks it over, submits their decision, and the workflow resumes with what they decided. You own the reviewer's experience completely — the layout, the branding, who can see what, how the decision is captured. Opus only hands over the item and waits for the answer. For reviews that happen inside Opus, use the [Review Task](/tasks/review). Off-Platform Review is for when the reviewer works in your application and never signs in to Opus. ## Key Capabilities Your system receives the reviewed step's inputs, outputs, schemas and execution metadata. Build the review screen in your own application, for people who have no Opus account. The output variables you add to the task are the decision form your system fills in. Whatever your reviewer returns is what later steps consume. ## When to Use It | Situation | Real-World Example | | - | - | | **Reviewers work elsewhere** | Claims assessors work in your operations console all day | | **Reviewers are external** | A partner approves output but has no Opus account | | **The review needs your context** | The screen must show account history Opus does not hold | | **Your own approval rules** | Routing, escalation and permissions already exist in your system | ## Setting It Up | Setting | What It Means | | - | - | | **Review Node** | The step being reviewed. This is the task's one input, and it carries that step's whole execution context | | **Output** | The decision fields your system sends back — a verdict, edited values, reviewer notes | | **Webhook URL** | The HTTPS endpoint Opus posts review requests to. Required | | **Webhook Headers** | Optional headers sent with every request, so your endpoint can confirm the call came from Opus | | **Timeout** | How long Opus waits for your endpoint to acknowledge the request. Defaults to 15 seconds | The webhook is configured per workspace when the task is connected, so the same task can point at a different endpoint in each workspace. Header values are encrypted at rest and are never shown again once saved. Off-Platform Reviews only run for a verified organization. An unverified organization cannot create one, and if the workflow reaches one anyway, nothing is sent to your webhook and the review fails. Make sure your organization is verified before you build against it. ## How to Add an Off-Platform Review Drag an Off-Platform Review from the sidebar and place it after the step you want reviewed. Set the Review Node input to the step whose output needs a human decision. Enter the webhook URL your reviewer application listens on, plus any authentication headers it expects. Add an output variable for each thing the reviewer decides. These become the form your system renders, and Opus rejects a callback returning anything you have not declared. Render the item from the request, collect the decision, and post it back to the callback URL that came with it. ## What Opus Sends ```json theme={null} { "execution_id": "c4e8a1f2-9b3d-4a7e-8f1c-2d6b5a9e3c14", "workflow_id": "wf_support_reply_v3", "workflow_name": "Customer Support Reply Pipeline", "inputs": { "review_node": { "type": "node", "display_name": "Review Node", "variable_name": "review_node", "value": { "node_execution_id": "ne_2b8c", "handler_id": "h_draft_reply", "handler_version_id": "hv_9c2e", "handler_active_id": "ha_7a2f", "handler_active_version_id": "hav_e41d", "input_schema": { "customer_message": { "variable_name": "customer_message", "display_name": "Customer Message", "allowed_types": [{ "type": "str" }] } }, "output_schema": { "draft_reply": { "variable_name": "draft_reply", "display_name": "Drafted Reply", "allowed_types": [{ "type": "str" }] } }, "input": { "customer_message": { "value": "I'm still being charged the old rate after upgrading.", "type": { "type": "str" } } }, "output": { "draft_reply": { "value": "Hi Sarah, thanks for reaching out — I've corrected the billing record and issued a $150 refund.", "type": { "type": "str" } } }, "process": {} } } }, "callback": { "url": "https://operator.opus.com/v1/execution/callback/c4e8a1f2-9b3d-4a7e-8f1c-2d6b5a9e3c14", "token": "wT8_kP3rN9vQ2xL5mY7jH4bC6dF1aE0sZ", "token_header": "X-Opus-Callback-Token" }, "expected_output_schema": { "final_reply": { "type": "str", "display_name": "Final Reply", "variable_name": "final_reply", "is_nullable": false }, "reviewer_notes": { "type": "str", "display_name": "Notes", "variable_name": "reviewer_notes", "is_nullable": false } } } ``` ### Inside the review node Everything the reviewer needs sits in `inputs.review_node.value`: | Field | What It Is | | - | - | | `input` | What the reviewed step received. Each entry carries its `value` and `type` | | `output` | What the reviewed step produced. Usually the thing being reviewed | | `input_schema` / `output_schema` | Field definitions for the values above — labels and types, for rendering each field with the right widget | | `process` | Execution metadata for the reviewed step | | `node_execution_id`, `handler_*` | Identifiers for the step and the version of it that ran | `expected_output_schema` is the decision form: one entry per output variable you defined, keyed by name, with the `type` your system must return and the `display_name` to label it with. Acknowledge the request with a `200` promptly — within the configured timeout, 15 seconds by default. This only confirms receipt; the decision comes later, as a separate request. Store the `execution_id`, the whole `callback` block, and the `expected_output_schema` before you reply. You need them when the reviewer submits, and Opus will not send them again. ## Sending the Decision Back Post to `callback.url`, putting `callback.token` in the header named by `callback.token_header`: ```bash theme={null} curl --request POST \ --url https://operator.opus.com/v1/execution/callback/c4e8a1f2-9b3d-4a7e-8f1c-2d6b5a9e3c14 \ --header 'Content-Type: application/json' \ --header 'X-Opus-Callback-Token: wT8_kP3rN9vQ2xL5mY7jH4bC6dF1aE0sZ' \ --data '{ "output_data": { "final_reply": "Hi Sarah, thanks for flagging this — the upgrade should have applied automatically. I have corrected the billing record and issued a $150 refund.", "reviewer_notes": "Softened the opener. Refund amount is correct." }, "status": "success" }' ``` Send **bare values**. Opus knows each field's type from the output variables you declared and applies it for you. Do not wrap values as `{ "value": …, "type": … }`. That wrapper is stored as the value itself, and the workflow resumes with data your later steps cannot read. Two patterns cover most review screens: * **Accept as-is** — pre-fill the form from `review_node.value.output` and submit it unchanged. * **Accept with edits** — the reviewer changes one or more fields, and those edited values are what later steps consume. Every key in `output_data` must be one you declared. An undeclared field is rejected with `422`, naming both what you sent and what was expected — nothing is stored and the workflow stays paused, so you can correct the payload and post again. If the review cannot be completed at all, report a failure instead of leaving the workflow waiting: ```json theme={null} { "status": "failed", "error": "No reviewer available before the claim deadline" } ``` ## How It Behaves Opus retries a failed request up to 3 times with exponential backoff. Network errors and the statuses `408`, `425`, `429`, `500`, `502`, `503` and `504` are treated as transient. Any other `4xx` is treated as a misconfigured webhook and fails immediately. After repeated failures a circuit breaker opens for 60 seconds. The callback token authenticates a single decision for a single execution, and is invalidated as soon as one succeeds. A second submission is rejected with `401`, so build for one reviewer per review and do not assume a request will be sent again. Keep the token server-side. It is the only credential needed to resolve the review, so it must never reach a browser. An execution accepts a decision only while it is still waiting. Once it has been completed or closed out by its deadline, a callback returns `401` with a message saying the execution is no longer accepting callbacks — the workflow has already moved on. Show the reviewer that the review expired, and do not let them retry. An off-platform review is resolved by your system, not by a person in Opus. Attempting to pick it up or complete it through the Opus review screens is rejected with `409`. For reviewers working inside Opus, use the [Review Task](/tasks/review). ## Responses You May Get | Status | Meaning | | - | - | | `200` | Decision accepted. The workflow resumes | | `401` | The token is wrong or spent, or the execution is no longer accepting callbacks | | `404` | No execution with that id | | `422` | `output_data` contains a field the task does not declare | ## Tips for Better Results Build one form field per entry in `expected_output_schema`, using `display_name` as the label and `type` to pick the widget. A decision field added to the task then appears in your UI without a code change. Reply `200` as soon as you have stored the request, then build the review screen. Loading related data before replying risks blowing the timeout and triggering a retry, which leaves you holding the same review twice. `review_node.value.input` is what the step was working from. A reviewer judging a drafted reply needs the customer's original message to judge it against. ## Related Hand any step to your own system, not just a review. Accept or reject a step's output inside Opus. Let a person choose which path the workflow takes. Have a person complete work inside Opus. # Off-Platform Task Source: https://developer.opus.com/tasks/off-platform-task Hand a step to your own system and let the workflow wait until your system sends the result back. The Off-Platform Task hands a step of your workflow to a system you run. Opus posts the task's inputs to a webhook you provide, pauses the workflow, and waits. When your system has done the work, it posts the result back and the workflow carries on from where it stopped. Use it when the work belongs somewhere else — your own operations console, a partner's system, a queue your team already watches — and you want the workflow to treat it as a normal step. For a plain REST call that returns its answer immediately, use [External Service](/tasks/data/external-service) instead. That task calls an API and continues with the response. Off-Platform Task is for work that takes its own time: the workflow stays paused, sometimes for hours, until your system calls back. ## Key Capabilities The work happens entirely in your application. Opus only hands over the inputs and waits for the answer. The step does not time out while your system works. It resumes on your callback. Every dispatch carries a single-use callback token, and you can add your own authentication headers. Transient failures reaching your webhook are retried automatically before the step is failed. ## When to Use It | Situation | Real-World Example | | - | - | | **Work happens in your app** | Your agents process claims in your own console, not in Opus | | **A partner system decides** | An external adjudicator returns an approval your workflow needs | | **Long-running work** | A batch job runs overnight and reports back in the morning | | **Your own queue** | The task joins a work queue your team already uses | ## Setting It Up | Setting | What It Means | | - | - | | **Input** | Variables from earlier in the workflow that your system receives | | **Output** | Variables your system must send back. These become available to later steps | | **Webhook URL** | The HTTPS endpoint Opus posts the task to. Required | | **Webhook Headers** | Optional headers sent with every dispatch, so your endpoint can confirm the call came from Opus | | **Timeout** | How long Opus waits for your endpoint to acknowledge the dispatch. Defaults to 15 seconds | The webhook is configured per workspace when the task is connected, so the same task can point at a different endpoint in each workspace. Header values are encrypted at rest and are never shown again once saved. Off-Platform Tasks only run for a verified organization. An unverified organization cannot create one, and if the workflow reaches one anyway, nothing is sent to your webhook and the step fails. Make sure your organization is verified before you build against it. ## How to Add an Off-Platform Task Drag an Off-Platform Task from the sidebar into your workflow. Enter the webhook URL your system listens on, and add any authentication headers your endpoint expects. Connect the variables from earlier steps that your system needs to do the work. Add the variables your system will send back. Later steps read these, and Opus rejects a callback that returns anything you have not declared here. Accept the dispatch, do the work, and post the result to the callback URL that came with it. ## What Opus Sends When the workflow reaches the task, Opus posts JSON to your webhook URL with your configured headers: ```json theme={null} { "execution_id": "c34d1def-b73c-43a8-8ead-1669e62cc5d5", "workflow_id": "d3e00db5-77ea-402a-8156-0a652734b90b", "workflow_name": "Claim Creation", "inputs": { "correlation_id": { "type": "str", "display_name": "Correlation Id", "variable_name": "correlation_id", "value": "CORR-FIX-UCRN100411575301" }, "claim_header": { "type": "object", "display_name": "Claim Header", "variable_name": "claim_header", "value": { "ucrn": "UCRN100411575301", "channel": "TP2" } } }, "callback": { "url": "https://operator.opus.com/v1/execution/callback/c34d1def-b73c-43a8-8ead-1669e62cc5d5", "token": "lTgmnk2-twSO34sgj9CBTMhD0ASnlrlz23byrYa3ffs", "token_header": "X-Opus-Callback-Token" }, "expected_output_schema": { "decision": { "type": "str", "display_name": "Decision", "variable_name": "decision", "description": "Review decision", "is_nullable": false }, "response_text": { "type": "str", "display_name": "Response Text", "variable_name": "response_text", "is_nullable": false } } } ``` | Field | What It Is | | - | - | | `execution_id` | Identifies this one execution. Log it — it ties your records to Opus's | | `inputs` | The input variables, each with its `type` and its `value` | | `callback` | Where to send the result, the token to send with it, and the header to put the token in | | `expected_output_schema` | The fields Opus expects back, keyed by name. Absent when the task declares no outputs | Acknowledge the dispatch with a `200` promptly — within the configured timeout, 15 seconds by default. This only confirms receipt. The actual result comes later, as a separate request. Store the `execution_id`, the whole `callback` block, and the `expected_output_schema` before you reply. You need them when the work finishes, and Opus will not send them again. ## Sending the Result Back Post to `callback.url`, putting `callback.token` in the header named by `callback.token_header`: ```bash theme={null} curl --request POST \ --url https://operator.opus.com/v1/execution/callback/c34d1def-b73c-43a8-8ead-1669e62cc5d5 \ --header 'Content-Type: application/json' \ --header 'X-Opus-Callback-Token: lTgmnk2-twSO34sgj9CBTMhD0ASnlrlz23byrYa3ffs' \ --data '{ "output_data": { "decision": "APPROVE", "response_text": "Verified against the provider invoice." }, "status": "success" }' ``` Send **bare values**. Opus knows each field's type from the output variables you declared — it appears in `expected_output_schema` — and applies it for you. Do not wrap values as `{ "value": …, "type": … }`. That wrapper is stored as the value itself, and the step resumes with data your later steps cannot read. Every key in `output_data` must be one you declared. An undeclared field is rejected with `422`, naming both what you sent and what was expected — nothing is stored and the workflow stays paused, so you can correct the payload and post again. ### When the Work Cannot Be Done Report a failure rather than leaving the workflow waiting: ```json theme={null} { "status": "failed", "error": "Claim could not be assessed: provider record unavailable" } ``` The execution is recorded as failed with your message. ## How It Behaves Opus retries a failed dispatch up to 3 times with exponential backoff. Network errors and the statuses `408`, `425`, `429`, `500`, `502`, `503` and `504` are treated as transient and retried. Any other `4xx` is treated as a misconfigured webhook and fails immediately without retrying. After repeated failures a circuit breaker opens for 60 seconds, so a struggling endpoint is not hammered by every execution at once. The token authenticates one result for one execution. It is invalidated the moment a callback succeeds, so a replayed request is rejected with `401`. Keep it server-side. It is the only credential needed to complete the step, so it must never reach a browser, a log you share, or a URL. An execution accepts a result only while it is still waiting. Once it has been completed or closed out by its deadline, a callback returns `401` with a message saying the execution is no longer accepting callbacks — the workflow has already moved on. Treat that as final. Do not retry it, and show your users that the work expired. An off-platform step is resolved by your system, not by a person in Opus. Attempting to pick it up or complete it through the Opus human-task screens is rejected with `409`. If you want a person working inside Opus, use [Opus Human Task](/tasks/agent/opus-human-task) instead. ## Responses You May Get | Status | Meaning | | - | - | | `200` | Result accepted. The workflow resumes | | `401` | The token is wrong or spent, or the execution is no longer accepting callbacks | | `404` | No execution with that id | | `422` | `output_data` contains a field the task does not declare | ## Tips for Better Results Reply `200` to the dispatch as soon as you have stored it, then do the work asynchronously. Fetching related data or rendering a screen before you reply risks blowing the timeout and triggering a retry, which leaves you handling the same execution twice. The output variables on the task are the contract. Adding a field in your system without adding it to the task turns a working integration into a `422`, so change the task first. Every dispatch and every result is tied to one `execution_id`. Logging it in your system makes a specific execution traceable end to end when something looks wrong. ## Related Send an earlier step's output out for review instead of dispatching arbitrary inputs. Call a REST API and continue immediately with its response. Have a person complete the work inside Opus. Accept or reject a step's output inside Opus. # Review Task Source: https://developer.opus.com/tasks/review Add quality checks to your workflow using human reviewers or AI validation. Review tasks let you check the quality of your workflow's output before moving on. You can have a real person review it (Human Review) or let AI check it automatically (Agentic Review). Only Opus Agent, Custom Agent, Human Task, and Text Extraction tasks can connect to a Review Task. Pause your workflow for a person to accept or reject the output. Let AI check the output and fix problems automatically. ## Human Review Human Review pauses your workflow so a real person can look at the output and decide whether to accept it or reject it. Use it when you need human judgment before moving forward. ### Key Capabilities Reviewers decide whether the output is good enough to continue. Reviewers can fix problems before the workflow continues. Give people a specific timeframe to complete their review. Route your workflow differently based on the reviewer's decision. ### When to Use It Use Human Review when you need a person to check the output before moving on: * Verify AI-generated content before publishing * Check that extracted data is accurate * Confirm output meets compliance requirements * Review flagged or uncertain results Need someone to fill in information instead of just approve/reject? Use [Opus Human Task](/tasks/agent/opus-human-task) instead. ### How to Add Human Review Drag a Human Review task into your workflow after the task you want reviewed. The review automatically inherits all inputs and outputs from the previous task. Explain what the reviewer should check and when to accept or reject. Choose how many hours the reviewer has to complete the review. Wire the Accept output to one path and the Reject output to another. Make sure both are connected. Run a preview to make sure both paths work as expected. Make sure you connect both the Accept and Reject paths to something. If you leave one unconnected, your workflow might not work correctly. ### Tips for Better Results Reviewers need to know exactly what to look for: * Explain what makes output acceptable * Give examples of what to accept vs. reject * List specific things to check Be realistic about deadlines: * Remember people work in different time zones * Allow time for thorough evaluation * Factor in editing time if you enabled it ## Agentic Review Agentic Review uses AI to check your workflow's output automatically. It can approve outputs that meet your criteria, flag problems, or even fix issues on its own—all without waiting for a person. Use it when you need to review lots of outputs quickly and consistently. Agentic Review is powered by **Opus Swarm**, a set of review agents created by AppliedAI. More agentic providers may be supported in the future. ### Key Capabilities AI checks outputs against your criteria automatically. Optionally fix problems without human involvement. Review thousands of outputs quickly and consistently. Route your workflow based on whether the output passes or fails. ### When to Use It Use Agentic Review when you need to check lots of outputs automatically: * Validate that data matches an expected format * Check that required fields are present * Fix common formatting issues automatically * Filter out outputs that need human attention Need human judgment or accountability? Use Human Review instead. Agentic Review works best when you can clearly define what "correct" looks like. ### How to Add Agentic Review Drag an Agentic Review task into your workflow after the task you want reviewed. The review automatically inherits all inputs and outputs from the previous task. Select the AI provider that will perform the review. Currently, **Opus Swarm** is available. Explain what makes output acceptable—what to check, required fields, expected formats. Wire the Pass output to one path and the Fail output to another. Make sure both are connected. Run a preview with both valid and invalid data to make sure both paths work. Make sure you connect both the Pass and Fail paths to something. If you leave one unconnected, your workflow might not work correctly. ### Tips for Better Results Vague criteria produce inconsistent results: * Good: "Date must be in YYYY-MM-DD format" * Bad: "Data should be correct" Before activating: * Try data that should pass * Try data that should fail * Make sure both paths work correctly ## Related Collect information from a person instead of just approve/reject. Let a person choose which path your workflow takes. Route your workflow automatically based on conditions. Learn how all the pieces fit together.