{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/clipform-io/json-schema/clipform-io-node-input-schema.json",
  "title": "NodeInput",
  "x-generated": "2026-11-04",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/clipform-io-openapi.yml#/components/schemas/NodeInput",
  "type": "object",
  "required": [
    "type",
    "prompt"
  ],
  "properties": {
    "id": {
      "type": "string",
      "format": "uuid",
      "description": "Optional client-generated node id (RF-style stable identity). When provided the node is inserted with this id so the builder's optimistic node needs no temp-id swap. Omit to let the server generate one.",
      "maxLength": 36
    },
    "type": {
      "$ref": "#/$defs/NodeType"
    },
    "prompt": {
      "type": "string",
      "maxLength": 500,
      "description": "The text shown to the respondent"
    },
    "label": {
      "type": "string",
      "description": "Internal short label used in exports and reports (defaults to prompt)",
      "maxLength": 2000
    },
    "required": {
      "type": "boolean",
      "default": true
    },
    "config": {
      "type": "object",
      "description": "Type-specific configuration. Key options by type:\n- choice: { choice, selection_mode, allow_text_response, randomise_options, show_option_count, option_display, content_media_type }\n- open: { formats, content_media_type, max_recording_seconds }\n- button: { button_text, button_style }\n- details: { title, fields, description, consent_items }\n- draw: { title, description, paper_color, stroke_colors, stroke_widths, diagram }\n- camera: { title, description, camera_facing, allowed_capture, camera_capture, allow_library_upload, capture_order, max_files, min_files }\n- payment: { amount, currency, provider, workspace_integration_id, title, description }\n- file_download: { files, button_text, description }\n- redirect: { url, auto_redirect }\n- end_screen: { title, message, show_score, icon, show_share_button, cta_type, cta_text, cta_url, score_ranges, scoring_results }\n"
    },
    "options": {
      "type": "array",
      "maxItems": 100,
      "items": {
        "type": "object",
        "required": [
          "content"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Client-generated option id (optional). When provided it's used as the row id so the builder's optimistic option is the persisted row (no temp id swap). Omit to let the server generate one.",
            "maxLength": 36
          },
          "content": {
            "type": "string",
            "maxLength": 200
          },
          "score": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Points awarded when this option is selected. Use `scores` instead to score across multiple named categories.",
            "format": "int32",
            "minimum": 0,
            "maximum": 2147483647
          },
          "scores": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "integer",
              "format": "int32",
              "minimum": 0,
              "maximum": 2147483647
            },
            "description": "Per-category scoring map. Keys are category names, values are points. -1 = knockout."
          }
        }
      },
      "description": "Answer options for choice/button nodes"
    }
  },
  "$defs": {
    "NodeType": {
      "type": "string",
      "enum": [
        "choice",
        "open",
        "button",
        "details",
        "draw",
        "camera",
        "payment",
        "file_download",
        "redirect",
        "end_screen"
      ]
    }
  }
}