# Create custom operator

```{raw} html
<div class="mo-api-page-show-toc" aria-hidden="true"></div>
```

Create a custom operator that can be used in workflows. Code type operators require source code or source file IDs; built-in binding types use base operators and binding configurations.

```text
POST https://moi.matrixorigin.cn/newmoi/workflow/v2/custom-operators
```

## Preparation before calling

Prepare a personal access token and target workspace ID that has access to the target workspace. First decide whether to create a code type or a built-in binding type, and prepare the corresponding implementation content.


## Request body

::::{div} mo-api-split
:::{div} mo-api-split-main

```{raw} html
<dl class="mo-api-fields">
  <div class="mo-api-field"><dt><code>name</code><span class="mo-api-field__type">string</span><span class="mo-api-field__required">Required</span></dt><dd>Operator name.</dd></div>
  <div class="mo-api-field"><dt><code>identifier</code><span class="mo-api-field__type">string</span><span class="mo-api-field__required">Required</span></dt><dd>Operator ID.</dd></div>
  <div class="mo-api-field"><dt><code>description</code><span class="mo-api-field__type">string</span><span class="mo-api-field__required">Required</span></dt><dd>Operator description.</dd></div>
  <div class="mo-api-field"><dt><code>kind</code><span class="mo-api-field__type">string</span></dt><dd>Operator type; when omitted, it is the code type.</dd></div>
  <div class="mo-api-field"><dt><code>language</code><span class="mo-api-field__type">string</span></dt><dd>The implementation language of the code type; currently only python is supported.</dd></div>
  <div class="mo-api-field"><dt><code>handler</code><span class="mo-api-field__type">string</span></dt><dd>Handler for the code type. Python processing functions use module and function names, such as main.handle; the corresponding function must accept three parameters: workspace_id, sdk and input.</dd></div>
  <div class="mo-api-field"><dt><code>input_schema</code><span class="mo-api-field__type">object</span><span class="mo-api-field__required">Required</span></dt><dd>Input definition. description must be provided for each properties entry.</dd></div>
  <div class="mo-api-field"><dt><code>output_schema</code><span class="mo-api-field__type">object</span><span class="mo-api-field__required">Required</span></dt><dd>Output definition. description must be provided for each properties entry.</dd></div>
  <div class="mo-api-field"><dt><code>version</code><span class="mo-api-field__type">string</span></dt><dd>Version for the code type.</dd></div>
  <div class="mo-api-field"><dt><code>isolation_level</code><span class="mo-api-field__type">string</span></dt><dd>Isolation configuration for the code type.</dd></div>
  <div class="mo-api-field"><dt><code>code</code><span class="mo-api-field__type">string</span></dt><dd>Source code for the code type; provide it instead of source_file_id.</dd></div>
  <div class="mo-api-field"><dt><code>source_file_id</code><span class="mo-api-field__type">string</span></dt><dd>Source file ID for the code type; provide it instead of code.</dd></div>
  <div class="mo-api-field"><dt><code>base_node_id</code><span class="mo-api-field__type">string</span></dt><dd>Base operator ID required by the built-in binding type.</dd></div>
  <div class="mo-api-field"><dt><code>base_node_version</code><span class="mo-api-field__type">string</span></dt><dd>Base operator version required by the built-in binding type.</dd></div>
  <div class="mo-api-field"><dt><code>binding_config</code><span class="mo-api-field__type">object</span></dt><dd>Binding configuration required by the built-in binding type.</dd></div>
  <div class="mo-api-field"><dt><code>node_id</code><span class="mo-api-field__type">string</span></dt><dd>Custom workflow operator ID. When omitted, the service generates it from the target workspace and identifier.</dd></div>
  <div class="mo-api-field"><dt><code>enabled</code><span class="mo-api-field__type">boolean</span></dt><dd>Whether to enable initially.</dd></div>
  <div class="mo-api-field"><dt><code>catalog_id</code><span class="mo-api-field__type">integer</span></dt><dd>Associated catalog ID.</dd></div>
  <div class="mo-api-field"><dt><code>database_id</code><span class="mo-api-field__type">integer</span></dt><dd>Associated database ID.</dd></div>
</dl>
```

:::
:::{div} mo-api-split-aside

```{raw} html
<p class="mo-api-example-label">Request example</p>
```

```bash
curl -X POST "https://moi.matrixorigin.cn/newmoi/workflow/v2/custom-operators" \
  -H "X-API-Key: $AI_STUDIO_API_KEY" \
  -H "X-Workspace-ID: $WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Text Counter",
    "identifier": "text_counter",
    "node_id": "moi:custom.operator:$WORKSPACE_ID:text_counter",
    "description": "Counts the number of characters in the input text.",
    "language": "python",
    "handler": "main.handle",
    "input_schema": {
      "type": "object",
      "properties": {
        "text": {
          "type": "string",
          "description": "The text to count."
        }
      }
    },
    "output_schema": {
      "type": "object",
      "properties": {
        "count": {
          "type": "integer",
          "description": "Character count."
        }
      }
    },
    "code": "def handle(workspace_id, sdk, input):\n    return {\"count\": len(input[\"text\"])}"
  }'
```

:::
::::

## Successful response

The response returns the ID and configuration of the newly created operator. Save the operator ID, which will be used for subsequent viewing, updating, trial running, activation, deactivation, and deletion.


The response fields are as follows.

::::{div} mo-api-split
:::{div} mo-api-split-main

```{raw} html
<dl class="mo-api-fields">
  <div class="mo-api-field"><dt><code>code</code><span class="mo-api-field__type">string</span></dt><dd>OK on success.</dd></div>
  <div class="mo-api-field"><dt><code>msg</code><span class="mo-api-field__type">string</span></dt><dd>OK on success.</dd></div>
  <div class="mo-api-field"><dt><code>data.id</code><span class="mo-api-field__type">integer</span></dt><dd>Newly created custom operator ID.</dd></div>
  <div class="mo-api-field"><dt><code>data.node_id</code><span class="mo-api-field__type">string</span></dt><dd>Operator ID in the workflow.</dd></div>
  <div class="mo-api-field"><dt><code>data.name</code><span class="mo-api-field__type">string</span></dt><dd>Operator name.</dd></div>
  <div class="mo-api-field"><dt><code>data.identifier</code><span class="mo-api-field__type">string</span></dt><dd>Operator ID.</dd></div>
  <div class="mo-api-field"><dt><code>data.description</code><span class="mo-api-field__type">string</span></dt><dd>Operator description; returned if there is a value.</dd></div>
  <div class="mo-api-field"><dt><code>data.language</code><span class="mo-api-field__type">integer</span></dt><dd>Implements the numerical encoding of the language. language usage string in request.</dd></div>
  <div class="mo-api-field"><dt><code>data.kind</code><span class="mo-api-field__type">integer</span></dt><dd>Numeric encoding of the operator type. kind usage string in request.</dd></div>
  <div class="mo-api-field"><dt><code>data.handler</code><span class="mo-api-field__type">string</span></dt><dd>Processing function; returned when there is a value.</dd></div>
  <div class="mo-api-field"><dt><code>data.version</code><span class="mo-api-field__type">string</span></dt><dd>Operator version; returned if there is a value.</dd></div>
  <div class="mo-api-field"><dt><code>data.isolation_level</code><span class="mo-api-field__type">string</span></dt><dd>Isolation configuration; returned if there is a value.</dd></div>
  <div class="mo-api-field"><dt><code>data.source_file_id</code><span class="mo-api-field__type">string</span></dt><dd>Source file ID; returned when created using a source file.</dd></div>
  <div class="mo-api-field"><dt><code>data.input_schema</code><span class="mo-api-field__type">string</span></dt><dd>Enter the defined serialization content.</dd></div>
  <div class="mo-api-field"><dt><code>data.output_schema</code><span class="mo-api-field__type">string</span></dt><dd>Output the defined serialized content.</dd></div>
  <div class="mo-api-field"><dt><code>data.created_by</code><span class="mo-api-field__type">string</span></dt><dd>Creator ID; returned if there is a value.</dd></div>
  <div class="mo-api-field"><dt><code>data.updated_by</code><span class="mo-api-field__type">string</span></dt><dd>Last updater ID; returned if there is a value.</dd></div>
  <div class="mo-api-field"><dt><code>data.created_at</code><span class="mo-api-field__type">integer</span></dt><dd>Creation timestamp; returned if there is a value.</dd></div>
  <div class="mo-api-field"><dt><code>data.updated_at</code><span class="mo-api-field__type">integer</span></dt><dd>Last updated timestamp; returned if there is a value.</dd></div>
  <div class="mo-api-field"><dt><code>data.base_node_id</code><span class="mo-api-field__type">string</span></dt><dd>The basic operator associated with the built-in binding type; returned when there is a value.</dd></div>
  <div class="mo-api-field"><dt><code>data.base_node_version</code><span class="mo-api-field__type">string</span></dt><dd>The basic operator version associated with the built-in binding type; returned when there is a value.</dd></div>
  <div class="mo-api-field"><dt><code>data.binding_config</code><span class="mo-api-field__type">string</span></dt><dd>The serialized content of the binding configuration; returned if there is a value.</dd></div>
  <div class="mo-api-field"><dt><code>data.catalog_id</code><span class="mo-api-field__type">integer</span></dt><dd>Associated Catalog ID; returned if there is a value.</dd></div>
  <div class="mo-api-field"><dt><code>data.database_id</code><span class="mo-api-field__type">integer</span></dt><dd>The associated database ID; returned if there is a value.</dd></div>
  <div class="mo-api-field"><dt><code>data.enabled</code><span class="mo-api-field__type">boolean</span></dt><dd>Whether the operator is enabled.</dd></div>
</dl>
```

:::
:::{div} mo-api-split-aside

```{raw} html
<p class="mo-api-example-label">Successful response example</p>
```

```json
{
  "code": "OK",
  "msg": "OK",
  "data": {
    "id": 123,
    "node_id": "moi:custom.operator:workspace:text_counter",
    "name": "Text Counter",
    "identifier": "text_counter",
    "language": 1,
    "kind": 1,
    "input_schema": "{\"type\":\"object\"}",
    "output_schema": "{\"type\":\"object\"}",
    "enabled": true
  }
}
```

:::
::::

## Error response

::::{div} mo-api-split
:::{div} mo-api-split-main

```{raw} html
<dl class="mo-api-fields">
  <div class="mo-api-field"><dt><code>code</code><span class="mo-api-field__type">string</span></dt><dd>Error code.</dd></div>
  <div class="mo-api-field"><dt><code>msg</code><span class="mo-api-field__type">string</span></dt><dd>Readable error message.</dd></div>
  <div class="mo-api-field"><dt><code>data</code><span class="mo-api-field__type">null</span></dt><dd>`null` in an error response.</dd></div>
</dl>
```

:::
:::{div} mo-api-split-aside

```{raw} html
<p class="mo-api-example-label">Error response example</p>
```

```json
{
  "code": "ErrParamInvalid",
  "msg": "请求参数无效",
  "data": null
}
```

:::
::::

## Follow-up operations

[Query custom operator details](get-custom-operator.md) or [Trial run custom operator](test-custom-operator.md).
