{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/tektolo-com/json-schema/tektolo-com-feedback-in-schema.json",
  "title": "FeedbackIn",
  "description": "What the site, a tool or an idea box sends to ``POST /v1/feedback``.",
  "x-generated": "2026-10-30",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/tektolo-com-openapi.json#/components/schemas/FeedbackIn",
  "properties": {
    "scope": {
      "type": "string",
      "enum": [
        "site",
        "tool",
        "idea"
      ],
      "title": "Scope",
      "description": "site, a specific tool, or an idea for a new tool."
    },
    "capability": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 64
        },
        {
          "type": "null"
        }
      ],
      "title": "Capability",
      "description": "Tool id when scope is tool."
    },
    "page": {
      "type": "string",
      "maxLength": 200,
      "title": "Page",
      "description": "Path of the page the feedback is about.",
      "default": "/"
    },
    "kind": {
      "type": "string",
      "enum": [
        "rating",
        "issue",
        "idea",
        "unmatched",
        "wtp"
      ],
      "title": "Kind",
      "default": "issue"
    },
    "rating": {
      "anyOf": [
        {
          "type": "string",
          "enum": [
            "useful",
            "not_quite"
          ]
        },
        {
          "type": "null"
        }
      ],
      "title": "Rating"
    },
    "reasons": {
      "items": {
        "type": "string",
        "enum": [
          "too_high",
          "too_low",
          "missing_items",
          "wrong_items",
          "confusing",
          "other"
        ]
      },
      "type": "array",
      "maxItems": 6,
      "title": "Reasons"
    },
    "message": {
      "type": "string",
      "maxLength": 2000,
      "title": "Message",
      "default": ""
    },
    "email": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 254
        },
        {
          "type": "null"
        }
      ],
      "title": "Email",
      "description": "Only if you want a reply."
    },
    "source": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 64
        },
        {
          "type": "null"
        }
      ],
      "title": "Source",
      "description": "Optional self-reported source; not verified provenance."
    },
    "reporter": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 64
        },
        {
          "type": "null"
        }
      ],
      "title": "Reporter",
      "description": "Optional reporter type, for example human or agent; self-reported."
    },
    "agent_name": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 128
        },
        {
          "type": "null"
        }
      ],
      "title": "Agent Name",
      "description": "Optional agent label. Do not include personal details or secrets."
    },
    "estimate": {
      "anyOf": [
        {
          "$ref": "#/$defs/EstimateContext"
        },
        {
          "type": "null"
        }
      ]
    },
    "wtp": {
      "anyOf": [
        {
          "$ref": "#/$defs/WtpAnswer"
        },
        {
          "type": "null"
        }
      ]
    },
    "finding_text": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 300
        },
        {
          "type": "null"
        }
      ],
      "title": "Finding Text",
      "description": "Unmatched kind only."
    },
    "website": {
      "type": "string",
      "title": "Website",
      "description": "Leave empty (spam trap).",
      "default": ""
    }
  },
  "type": "object",
  "required": [
    "scope"
  ],
  "$defs": {
    "EstimateContext": {
      "properties": {
        "result_hash": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 71,
              "pattern": "^sha256:[0-9a-f]{8,64}$"
            },
            {
              "type": "null"
            }
          ],
          "title": "Result Hash"
        },
        "input_hash": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 71,
              "pattern": "^sha256:[0-9a-f]{8,64}$"
            },
            {
              "type": "null"
            }
          ],
          "title": "Input Hash"
        },
        "ruleset_version": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 40,
              "pattern": "^[0-9A-Za-z.+-]{1,40}$"
            },
            {
              "type": "null"
            }
          ],
          "title": "Ruleset Version"
        },
        "contract_version": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 40,
              "pattern": "^[0-9A-Za-z.+-]{1,40}$"
            },
            {
              "type": "null"
            }
          ],
          "title": "Contract Version"
        },
        "cbsa": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 5,
              "pattern": "^\\d{5}$"
            },
            {
              "type": "null"
            }
          ],
          "title": "Cbsa"
        },
        "expected": {
          "anyOf": [
            {
              "type": "number",
              "maximum": 1000000000.0,
              "minimum": 0.0
            },
            {
              "type": "null"
            }
          ],
          "title": "Expected"
        }
      },
      "type": "object",
      "title": "EstimateContext",
      "description": "Identifiers of the estimate being rated. Hashes, versions, region and total only.\n\nEvery field has a strict format (security review M1): they end up in the feedback digest,\nso nothing here may carry free text."
    },
    "WtpAnswer": {
      "properties": {
        "choice": {
          "type": "string",
          "enum": [
            "per_move_out",
            "monthly",
            "not_at_all"
          ],
          "title": "Choice"
        },
        "amount_usd": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 12
            },
            {
              "type": "null"
            }
          ],
          "title": "Amount Usd"
        },
        "payment_model": {
          "anyOf": [
            {
              "type": "string",
              "enum": [
                "balance",
                "monthly",
                "no_preference"
              ]
            },
            {
              "type": "null"
            }
          ],
          "title": "Payment Model"
        },
        "minimum_topup_usd": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 12
            },
            {
              "type": "null"
            }
          ],
          "title": "Minimum Topup Usd"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "choice"
      ],
      "title": "WtpAnswer",
      "description": "Optional price evidence, never a quoted offer or a payment instruction."
    }
  }
}