> ## Documentation Index
> Fetch the complete documentation index at: https://developer.opus.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a Code Node

> 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.

<Note>
  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.
</Note>

## Headers

<ParamField header="x-service-key" type="string" required>
  Your API authentication key
</ParamField>

## Body Parameters

The code node is nested under a `code` key.

<ParamField body="code" type="object" required>
  The code node to create. Fields below.
</ParamField>

<ParamField body="code.name" type="string" required>
  Code node display name. Maximum 255 characters.
</ParamField>

<ParamField body="code.description" type="string" required>
  What the code does, shown under its name. Maximum 2048 characters.
</ParamField>

<ParamField body="code.icon" type="string" required>
  Code icon as a base64-encoded SVG (or PNG) — a plain string, with no `data:` prefix. Maximum 65535 characters.
</ParamField>

<ParamField body="code.sourceCode" type="string" required>
  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).
</ParamField>

<ParamField body="code.categories" type="string[]" required>
  Categories the code node is filed under in the marketplace. Maximum 5 entries. See [Categories](#categories).
</ParamField>

<ParamField body="code.inputs" type="object">
  The node's input schema, keyed by each variable's `variableName`. Maximum 100 entries and 512KB JSON-encoded. See [Variable object](#variable-object).
</ParamField>

<ParamField body="code.outputs" type="object">
  The node's output schema, keyed by each variable's `variableName`. Same shape and limits as `inputs`.
</ParamField>

<ParamField body="code.status" type="string" default="active">
  Code status — `active`, `inactive`, `soon` or `deprecated`.
</ParamField>

<ParamField body="code.isNew" type="boolean" default="true">
  Show the "new" badge on the code tile.
</ParamField>

<ParamField body="code.isPopular" type="boolean" default="false">
  Show the "popular" badge on the code tile.
</ParamField>

<ParamField body="code.isBeta" type="boolean" default="false">
  Show the "beta" badge on the code tile.
</ParamField>

<Note>
  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.
</Note>

## Variable object

Each value inside `inputs` and `outputs`. The map key must equal the variable's `variableName`.

<ParamField body="id" type="string" required>
  Stable identifier for the variable, unique within the schema. Maximum 255 characters.
</ParamField>

<ParamField body="variableName" type="string" required>
  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.
</ParamField>

<ParamField body="allowedTypes" type="object[]" required>
  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`.
</ParamField>

<ParamField body="displayName" type="string">
  Human-readable label rendered in the workflow builder. Maximum 255 characters. When omitted, the code service applies its own default.
</ParamField>

<ParamField body="description" type="string">
  Description shown next to the variable in the builder. Maximum 2048 characters.
</ParamField>

<ParamField body="default" type="any" default="null">
  Pre-filled default value. Its type must match one of `allowedTypes`.
</ParamField>

<ParamField body="isNullable" type="boolean" default="false">
  When true, the workflow may leave this variable unset.
</ParamField>

<ParamField body="tags" type="object[]">
  Annotations the builder uses for grouping and filtering, each `{ variableName, value, description }`. Maximum 20.
</ParamField>

<ParamField body="options" type="any[]">
  Enum-style choice list. When non-empty the builder renders a dropdown. Each entry is free-form JSON. Maximum 20.
</ParamField>

<ParamField body="currentType" type="string">
  Which of `allowedTypes` is currently active. Must be one of them — consumers fall back to the first entry when unset.
</ParamField>

<ParamField body="nonEditableFields" type="string[]">
  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.
</ParamField>

<ParamField body="canDelete" type="boolean" default="true">
  When false, the builder hides the "remove variable" affordance.
</ParamField>

<Note>
  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.
</Note>

## 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

<ResponseField name="id" type="string" required>
  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.
</ResponseField>

<ResponseField name="name" type="string" required>
  Code node display name.
</ResponseField>

<ResponseField name="description" type="string">
  Code node description.
</ResponseField>

<ResponseField name="versionId" type="string">
  Id of the version this call created.
</ResponseField>

<Note>
  The response echoes only these four fields. `icon`, `categories`, `status` and the badge flags are stored but not returned.
</Note>

## Errors

<ResponseField name="400" type="Bad Request">
  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.
</ResponseField>

<ResponseField name="401" type="Unauthorized">
  Missing, invalid, or expired API key.
</ResponseField>

<ResponseField name="403" type="Forbidden">
  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.
</ResponseField>

<RequestExample>
  ```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);
  ```
</RequestExample>

<ResponseExample>
  ```json 201 Response theme={null}
  {
    "id": "{CODE_ID}",
    "name": "Normalize Text",
    "description": "Collapses runs of whitespace in OCR output",
    "versionId": "{CODE_VERSION_ID}"
  }
  ```
</ResponseExample>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.