{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/tektolo-com/json-schema/tektolo-com-scope-request-schema.json",
  "title": "ScopeRequest",
  "x-generated": "2026-10-30",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/tektolo-com-openapi.json#/components/schemas/ScopeRequest",
  "properties": {
    "client_refs": {
      "anyOf": [
        {
          "additionalProperties": {
            "type": "string"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "title": "Client Refs",
      "description": "Your own reference ids (e.g. unit_id, job_id). Echoed back, never used."
    },
    "property": {
      "$ref": "#/$defs/PropertyProfile",
      "description": "The unit: ZIP, size, type and year built."
    },
    "findings": {
      "items": {
        "$ref": "#/$defs/Finding"
      },
      "type": "array",
      "maxItems": 200,
      "title": "Findings",
      "description": "Move-out inspection findings, one per observed condition, coded."
    },
    "standards": {
      "$ref": "#/$defs/Standards",
      "description": "Finish profile, price tier and overrides."
    },
    "rate_card": {
      "items": {
        "$ref": "#/$defs/RateCardEntry"
      },
      "type": "array",
      "maxItems": 300,
      "title": "Rate Card",
      "description": "Your own prices by trade or task; they replace the regional library prices."
    },
    "trade_vendors": {
      "additionalProperties": {
        "$ref": "#/$defs/Vendor"
      },
      "propertyNames": {
        "$ref": "#/$defs/Trade"
      },
      "type": "object",
      "title": "Trade Vendors",
      "description": "Vendor (name, contact) to put on each trade's lines."
    },
    "constraints": {
      "$ref": "#/$defs/Constraints",
      "description": "Target ready date, whether the unit is occupied, access notes."
    },
    "tax_rate": {
      "anyOf": [
        {
          "type": "number",
          "maximum": 0.2,
          "minimum": 0.0
        },
        {
          "type": "string",
          "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"
        },
        {
          "type": "null"
        }
      ],
      "title": "Tax Rate",
      "description": "Applied to all lines, e.g. 0.07."
    },
    "decisions": {
      "items": {
        "$ref": "#/$defs/Decision"
      },
      "type": "array",
      "maxItems": 500,
      "title": "Decisions",
      "description": "Approve, decline or defer lines or findings from an earlier scope."
    },
    "read": {
      "type": "string",
      "enum": [
        "parser",
        "ai"
      ],
      "title": "Read",
      "description": "Deprecated and ignored: scope reads no free text.",
      "default": "parser"
    },
    "retain": {
      "type": "boolean",
      "title": "Retain",
      "description": "false: keep none of this request's text.",
      "default": true
    },
    "detail": {
      "type": "string",
      "enum": [
        "summary",
        "full"
      ],
      "title": "Detail",
      "description": "summary (small): totals, trade scopes, lines tied to findings. full: all.",
      "default": "full"
    }
  },
  "additionalProperties": false,
  "type": "object",
  "required": [
    "property"
  ],
  "$defs": {
    "Area": {
      "type": "string",
      "enum": [
        "whole_unit",
        "kitchen",
        "living_room",
        "dining_room",
        "bedroom",
        "bathroom",
        "hallway",
        "entry",
        "laundry",
        "closet",
        "garage",
        "patio_balcony",
        "exterior",
        "yard",
        "other"
      ],
      "title": "Area"
    },
    "Constraints": {
      "properties": {
        "target_ready_date": {
          "anyOf": [
            {
              "type": "string",
              "format": "date"
            },
            {
              "type": "null"
            }
          ],
          "title": "Target Ready Date"
        },
        "occupied": {
          "type": "boolean",
          "title": "Occupied",
          "description": "Work happens while occupied.",
          "default": false
        },
        "access_notes": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 500
            },
            {
              "type": "null"
            }
          ],
          "title": "Access Notes"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "title": "Constraints"
    },
    "Decision": {
      "properties": {
        "line_id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Line Id"
        },
        "finding_id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Finding Id"
        },
        "action": {
          "type": "string",
          "enum": [
            "approve",
            "decline",
            "defer"
          ],
          "title": "Action"
        },
        "note": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 300
            },
            {
              "type": "null"
            }
          ],
          "title": "Note"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "action"
      ],
      "title": "Decision",
      "description": "Owner decision. Re-run the same request with decisions to get the approved scope."
    },
    "Evidence-Input": {
      "properties": {
        "kind": {
          "$ref": "#/$defs/EvidenceKind"
        },
        "material": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 80
            },
            {
              "type": "null"
            }
          ],
          "title": "Material",
          "description": "What was tested, e.g. 'kitchen floor tile'."
        },
        "result": {
          "$ref": "#/$defs/EvidenceResult"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "kind",
        "result"
      ],
      "title": "Evidence",
      "description": "A negative or working result clears: inspector any hazard; lab mold, lead, asbestos, drugs, sewage; meter moisture; self_test or checklist a device."
    },
    "EvidenceKind": {
      "type": "string",
      "enum": [
        "self_test",
        "lab",
        "meter",
        "checklist",
        "inspector"
      ],
      "title": "EvidenceKind"
    },
    "EvidenceResult": {
      "type": "string",
      "enum": [
        "negative",
        "positive",
        "working",
        "failed"
      ],
      "title": "EvidenceResult"
    },
    "Extent": {
      "type": "string",
      "enum": [
        "spot",
        "partial",
        "full"
      ],
      "title": "Extent"
    },
    "Extraction": {
      "properties": {
        "method": {
          "type": "string",
          "enum": [
            "ai",
            "ai_document"
          ],
          "title": "Method",
          "description": "ai: free text; ai_document: an upload's page."
        },
        "model": {
          "type": "string",
          "maxLength": 80,
          "pattern": "^[A-Za-z0-9._:() -]+$",
          "title": "Model",
          "description": "The model that read it."
        },
        "confidence": {
          "anyOf": [
            {
              "type": "number",
              "maximum": 1.0,
              "minimum": 0.0
            },
            {
              "type": "string",
              "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"
            }
          ],
          "title": "Confidence",
          "description": "0 to 1."
        },
        "page": {
          "anyOf": [
            {
              "type": "integer",
              "maximum": 100.0,
              "minimum": 1.0
            },
            {
              "type": "null"
            }
          ],
          "title": "Page",
          "description": "ai_document: the page read."
        },
        "quote": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 300
            },
            {
              "type": "null"
            }
          ],
          "title": "Quote",
          "description": "ai_document: the row's words, contacts masked."
        },
        "cell": {
          "anyOf": [
            {
              "type": "string",
              "enum": [
                "move_out",
                "move_in",
                "comment"
              ]
            },
            {
              "type": "null"
            }
          ],
          "title": "Cell",
          "description": "ai_document: the cell read; move_in bills nothing, a hazard there is Possible."
        },
        "review": {
          "anyOf": [
            {
              "$ref": "#/$defs/ExtractionReview"
            },
            {
              "type": "null"
            }
          ],
          "description": "ai_document: the person's review."
        },
        "prompt_version": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 40,
              "pattern": "^[A-Za-z0-9._:-]+$"
            },
            {
              "type": "null"
            }
          ],
          "title": "Prompt Version",
          "description": "The reader's prompt version."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "method",
        "model",
        "confidence"
      ],
      "title": "Extraction",
      "description": "How our AI reader read a finding; never changes the price."
    },
    "ExtractionReview": {
      "properties": {
        "outcome": {
          "type": "string",
          "enum": [
            "confirmed",
            "accepted",
            "edited"
          ],
          "title": "Outcome"
        },
        "flags": {
          "items": {
            "type": "string",
            "enum": [
              "low_confidence",
              "medium_confidence",
              "quote_not_on_page",
              "count_unread",
              "column_unclear",
              "ok_unclear",
              "unmatched",
              "ai_match"
            ]
          },
          "type": "array",
          "maxItems": 8,
          "title": "Flags",
          "description": "Why the page flagged it."
        },
        "changed": {
          "items": {
            "type": "string",
            "enum": [
              "description",
              "area",
              "label",
              "extent",
              "quantity"
            ]
          },
          "type": "array",
          "maxItems": 5,
          "title": "Changed",
          "description": "edited: the fields changed."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "outcome"
      ],
      "title": "ExtractionReview",
      "description": "A person's review of a finding read from a document."
    },
    "Finding": {
      "properties": {
        "id": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 40,
              "pattern": "^[A-Za-z0-9_.:-]+$"
            },
            {
              "type": "null"
            }
          ],
          "title": "Id",
          "description": "Your id; defaults to f1, f2, ... in order."
        },
        "location": {
          "$ref": "#/$defs/Location",
          "description": "{\"area\": \"bedroom\", \"label\": \"Bedroom 2\"} or \"Bedroom 2\"; older form of rooms."
        },
        "code": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 80
            },
            {
              "type": "null"
            }
          ],
          "title": "Code",
          "description": "From property_turnover_issue_codes; general.manual_quote if none fits. Send it on every finding."
        },
        "description": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 300
            },
            {
              "type": "null"
            }
          ],
          "title": "Description",
          "description": "Deprecated; send code, with the words in source_text."
        },
        "extent": {
          "anyOf": [
            {
              "$ref": "#/$defs/Extent"
            },
            {
              "type": "null"
            }
          ],
          "description": "Only when the words say how far; else the code's default."
        },
        "quantity": {
          "anyOf": [
            {
              "$ref": "#/$defs/Quantity"
            },
            {
              "type": "null"
            }
          ],
          "description": "Measured amount (120 sq_ft), only as the words give it."
        },
        "notes": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 1000
            },
            {
              "type": "null"
            }
          ],
          "title": "Notes",
          "description": "More words; never billed or coded from."
        },
        "extraction": {
          "anyOf": [
            {
              "$ref": "#/$defs/Extraction"
            },
            {
              "type": "null"
            }
          ],
          "description": "Set by our AI reader; send it back unchanged."
        },
        "confirmed": {
          "type": "boolean",
          "title": "Confirmed",
          "description": "true: the person checked this AI-read finding.",
          "default": false
        },
        "signature_like": {
          "type": "boolean",
          "title": "Signature Like",
          "description": "Set by our reader; send it back unchanged.",
          "default": false
        },
        "rooms": {
          "anyOf": [
            {
              "$ref": "#/$defs/Rooms"
            },
            {
              "type": "null"
            }
          ],
          "description": "Which rooms: {\"area\": \"bedroom\", \"count\": 3} is all 3 bedrooms; labels name them."
        },
        "area_sq_ft": {
          "anyOf": [
            {
              "type": "number",
              "maximum": 100000.0,
              "exclusiveMinimum": 0.0
            },
            {
              "type": "string",
              "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"
            },
            {
              "type": "null"
            }
          ],
          "title": "Area Sq Ft",
          "description": "Measured area in sq ft; wins over a derived size."
        },
        "material": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 80
            },
            {
              "type": "null"
            }
          ],
          "title": "Material",
          "description": "The material as written, e.g. '9x9 vinyl tile'."
        },
        "year_statement": {
          "anyOf": [
            {
              "$ref": "#/$defs/YearStatement"
            },
            {
              "type": "null"
            }
          ],
          "description": "A year said in passing (\"built 1972\"); never sets property.year_built."
        },
        "status": {
          "$ref": "#/$defs/FindingStatus",
          "description": "Only needed (the default) bills; on a hazard, done/ok/none without evidence stays Possible.",
          "default": "needed"
        },
        "evidence": {
          "anyOf": [
            {
              "$ref": "#/$defs/Evidence-Input"
            },
            {
              "type": "null"
            }
          ],
          "description": "The test behind the finding; the only thing that clears a hazard."
        },
        "repeat_of": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 40,
              "pattern": "^[A-Za-z0-9_.:-]+$"
            },
            {
              "type": "null"
            }
          ],
          "title": "Repeat Of",
          "description": "Id of an earlier finding this repeats in its own rooms (\"same as above\"); it bills."
        },
        "source_text": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 1000
            },
            {
              "type": "null"
            }
          ],
          "title": "Source Text",
          "description": "The original words. Scanned for hazards; never billed or coded from."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "title": "Finding",
      "description": "One observed condition, coded from the issue-code catalog."
    },
    "FindingStatus": {
      "type": "string",
      "enum": [
        "needed",
        "done",
        "ok",
        "none"
      ],
      "title": "FindingStatus"
    },
    "FloorCoverings": {
      "properties": {
        "carpet_present": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "title": "Carpet Present",
          "description": "Is there wall-to-wall carpet? Omit if unknown."
        },
        "carpet_sq_ft": {
          "anyOf": [
            {
              "type": "integer",
              "maximum": 20000.0,
              "minimum": 0.0
            },
            {
              "type": "null"
            }
          ],
          "title": "Carpet Sq Ft",
          "description": "Carpeted area; omit to assume 60% of the floor area."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "title": "FloorCoverings",
      "description": "What is on the floors. Drives the carpet-cleaning baseline and whole-unit carpet sizes."
    },
    "Location": {
      "properties": {
        "area": {
          "$ref": "#/$defs/Area",
          "default": "whole_unit"
        },
        "label": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 60
            },
            {
              "type": "null"
            }
          ],
          "title": "Label",
          "description": "e.g. 'Bedroom 2'."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "title": "Location",
      "description": "Where; a plain string works too."
    },
    "Occupants": {
      "properties": {
        "child_under_6": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "title": "Child Under 6",
          "description": "A child under 6 lives there or is expected to."
        },
        "elderly": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "title": "Elderly",
          "description": "Housing for the elderly (62+) or disabled; not just an older tenant."
        },
        "hud_assisted": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "title": "Hud Assisted"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "title": "Occupants",
      "description": "property.occupants: lead-rule facts about the unit; leave out what is unknown."
    },
    "PriceTier": {
      "type": "string",
      "enum": [
        "bulk_contract",
        "pm_vendor",
        "retail_one_off"
      ],
      "title": "PriceTier",
      "description": "Purchasing channel. Library prices are pm_vendor (a PM buying turns from a local vendor)."
    },
    "Profile": {
      "type": "string",
      "enum": [
        "minimum",
        "standard",
        "premium"
      ],
      "title": "Profile"
    },
    "PropertyProfile": {
      "properties": {
        "zip": {
          "type": "string",
          "pattern": "^\\d{5}$",
          "title": "Zip",
          "description": "5-digit US ZIP code (no street address)."
        },
        "unit_type": {
          "$ref": "#/$defs/UnitType",
          "description": "Single-family homes and townhomes get house-sized defaults (floor area, locks).",
          "default": "apartment"
        },
        "bedrooms": {
          "type": "integer",
          "maximum": 12.0,
          "minimum": 0.0,
          "title": "Bedrooms",
          "description": "0 for a studio."
        },
        "bathrooms": {
          "anyOf": [
            {
              "type": "number",
              "multipleOf": 0.5,
              "maximum": 12.0,
              "minimum": 0.0
            },
            {
              "type": "string",
              "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"
            }
          ],
          "title": "Bathrooms",
          "description": "Half baths count as 0.5."
        },
        "sq_ft": {
          "anyOf": [
            {
              "type": "integer",
              "maximum": 20000.0,
              "minimum": 150.0
            },
            {
              "type": "null"
            }
          ],
          "title": "Sq Ft",
          "description": "Interior sq ft."
        },
        "year_built": {
          "anyOf": [
            {
              "type": "integer",
              "maximum": 2100.0,
              "minimum": 1700.0
            },
            {
              "type": "null"
            }
          ],
          "title": "Year Built",
          "description": "Drives lead-paint (pre-1978) handling."
        },
        "floor_coverings": {
          "$ref": "#/$defs/FloorCoverings"
        },
        "pets": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "title": "Pets",
          "description": "Did pets live in the unit? true adds an optional flea treatment. Omit if unknown."
        },
        "occupants": {
          "anyOf": [
            {
              "$ref": "#/$defs/Occupants"
            },
            {
              "type": "null"
            }
          ]
        },
        "walk_date": {
          "anyOf": [
            {
              "type": "string",
              "format": "date"
            },
            {
              "type": "null"
            }
          ],
          "title": "Walk Date",
          "description": "The walk-through date; dated or aged items are judged against it. Omit if unknown."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "zip",
        "bedrooms",
        "bathrooms"
      ],
      "title": "PropertyProfile"
    },
    "Quantity": {
      "properties": {
        "value": {
          "anyOf": [
            {
              "type": "number",
              "maximum": 100000.0,
              "exclusiveMinimum": 0.0
            },
            {
              "type": "string",
              "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"
            }
          ],
          "title": "Value"
        },
        "uom": {
          "$ref": "#/$defs/Uom"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "value",
        "uom"
      ],
      "title": "Quantity"
    },
    "RateCardEntry": {
      "properties": {
        "task_id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Task Id",
          "description": "A task_id from a result line, e.g. 'carpet.clean'."
        },
        "trade": {
          "anyOf": [
            {
              "$ref": "#/$defs/Trade"
            },
            {
              "type": "null"
            }
          ]
        },
        "unit_price": {
          "anyOf": [
            {
              "type": "number",
              "minimum": 0.0
            },
            {
              "type": "string",
              "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"
            },
            {
              "type": "null"
            }
          ],
          "title": "Unit Price",
          "description": "USD per uom; on a trade entry, uom 'hour' is its labor rate."
        },
        "uom": {
          "anyOf": [
            {
              "$ref": "#/$defs/Uom"
            },
            {
              "type": "null"
            }
          ],
          "description": "Required with a trade unit_price; a task in another uom ignores it."
        },
        "min_charge": {
          "anyOf": [
            {
              "type": "number",
              "minimum": 0.0
            },
            {
              "type": "string",
              "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"
            },
            {
              "type": "null"
            }
          ],
          "title": "Min Charge",
          "description": "USD per trade visit."
        },
        "trip_charge": {
          "anyOf": [
            {
              "type": "number",
              "minimum": 0.0
            },
            {
              "type": "string",
              "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"
            },
            {
              "type": "null"
            }
          ],
          "title": "Trip Charge",
          "description": "USD per trade visit."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "title": "RateCardEntry",
      "description": "Your price for a task_id (from a result line) or a trade, e.g. {\"trade\": \"handyman\", \"unit_price\": 65, \"uom\": \"hour\"}."
    },
    "Rooms": {
      "properties": {
        "area": {
          "$ref": "#/$defs/Area",
          "description": "Left out, from the labels, else the whole unit.",
          "default": "whole_unit"
        },
        "labels": {
          "items": {
            "type": "string"
          },
          "type": "array",
          "maxItems": 12,
          "title": "Labels",
          "description": "The rooms' names as written, e.g. ['Bedroom 2']."
        },
        "count": {
          "type": "integer",
          "maximum": 50.0,
          "minimum": 1.0,
          "title": "Count",
          "description": "At least the number of labels; capped at the unit's count.",
          "default": 1
        }
      },
      "additionalProperties": false,
      "type": "object",
      "title": "Rooms",
      "description": "Which rooms a finding covers."
    },
    "Standards": {
      "properties": {
        "profile": {
          "$ref": "#/$defs/Profile",
          "description": "minimum (rent-ready basics) | standard | premium (higher finish).",
          "default": "standard"
        },
        "overrides": {
          "$ref": "#/$defs/StandardsOverrides"
        },
        "price_tier": {
          "$ref": "#/$defs/PriceTier",
          "description": "bulk_contract (portfolio contract prices) | pm_vendor (default: a property manager buying turns from local vendors) | retail_one_off (an owner hiring one contractor).",
          "default": "pm_vendor"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "title": "Standards"
    },
    "StandardsOverrides": {
      "properties": {
        "paint_policy": {
          "anyOf": [
            {
              "type": "string",
              "enum": [
                "touch_up",
                "full_if_needed",
                "always_full"
              ]
            },
            {
              "type": "null"
            }
          ],
          "title": "Paint Policy"
        },
        "carpet_policy": {
          "anyOf": [
            {
              "type": "string",
              "enum": [
                "clean",
                "replace_if_damaged",
                "always_replace"
              ]
            },
            {
              "type": "null"
            }
          ],
          "title": "Carpet Policy"
        },
        "cleaning_policy": {
          "anyOf": [
            {
              "type": "string",
              "enum": [
                "standard",
                "deep"
              ]
            },
            {
              "type": "null"
            }
          ],
          "title": "Cleaning Policy"
        },
        "always_rekey": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "title": "Always Rekey"
        },
        "markup_pct": {
          "anyOf": [
            {
              "type": "number",
              "maximum": 100.0,
              "minimum": 0.0
            },
            {
              "type": "string",
              "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"
            },
            {
              "type": "null"
            }
          ],
          "title": "Markup Pct",
          "description": "Management markup applied to every line, %."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "title": "StandardsOverrides"
    },
    "Trade": {
      "type": "string",
      "enum": [
        "hauling",
        "handyman",
        "drywall",
        "painter",
        "flooring",
        "carpet_cleaning",
        "cleaning",
        "appliance",
        "plumber",
        "electrician",
        "hvac",
        "locksmith",
        "pest_control",
        "landscaping",
        "window_glass",
        "environmental",
        "structural"
      ],
      "title": "Trade"
    },
    "UnitType": {
      "type": "string",
      "enum": [
        "apartment",
        "single_family",
        "townhome",
        "condo",
        "duplex",
        "manufactured"
      ],
      "title": "UnitType"
    },
    "Uom": {
      "type": "string",
      "enum": [
        "each",
        "sq_ft",
        "sq_ft_floor",
        "sq_yd",
        "linear_ft",
        "room",
        "unit",
        "bedroom",
        "bathroom",
        "hour",
        "cu_yd",
        "visit"
      ],
      "title": "Uom"
    },
    "Vendor": {
      "properties": {
        "name": {
          "type": "string",
          "maxLength": 120,
          "title": "Name"
        },
        "contact": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 200
            },
            {
              "type": "null"
            }
          ],
          "title": "Contact"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "name"
      ],
      "title": "Vendor"
    },
    "YearStatement": {
      "properties": {
        "text": {
          "type": "string",
          "maxLength": 200,
          "minLength": 1,
          "title": "Text",
          "description": "The words, e.g. 'built in 1972'."
        },
        "year": {
          "anyOf": [
            {
              "type": "integer",
              "maximum": 2100.0,
              "minimum": 1700.0
            },
            {
              "type": "null"
            }
          ],
          "title": "Year",
          "description": "Left out when the words name none ('Victorian')."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "text"
      ],
      "title": "YearStatement",
      "description": "When the words say it was built."
    }
  }
}