{
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "postal_code": {
      "type": "string",
      "minLength": 1,
      "maxLength": 7,
      "pattern": "^[ABCEGHJKLMNPRSTVXYabceghjklmnprstvxy][0-9][ABCEGHJKLMNPRSTVWXYZabceghjklmnprstvwxyz](?: ?[0-9][ABCEGHJKLMNPRSTVWXYZabceghjklmnprstvwxyz][0-9])?$"
    },
    "region": {
      "type": "string",
      "enum": [
        "toronto_gta",
        "metro_vancouver"
      ]
    },
    "service": {
      "type": "string",
      "enum": [
        "regular",
        "deep",
        "move_in_out",
        "post_renovation",
        "office",
        "one_time",
        "maid",
        "condo",
        "apartment",
        "airbnb",
        "eco_friendly",
        "carpet",
        "re_clean"
      ],
      "x-labels": {
        "regular": "Regular cleaning",
        "deep": "Deep cleaning",
        "move_in_out": "Move in/out cleaning",
        "post_renovation": "Post-renovation cleaning",
        "office": "Office cleaning",
        "one_time": "One-time cleaning",
        "maid": "Maid service",
        "condo": "Condo cleaning",
        "apartment": "Apartment cleaning",
        "airbnb": "Airbnb turnover cleaning",
        "eco_friendly": "Eco-friendly cleaning",
        "carpet": "Carpet cleaning",
        "re_clean": "Re-clean"
      },
      "x-bookingkoala": {
        "regular": "General Cleaning",
        "deep": "General Cleaning",
        "move_in_out": "Move-In/Out Cleaning",
        "post_renovation": "Post-Renovation Cleaning",
        "airbnb": "TurnOver/AirBnB Cleaning",
        "office": "Office Cleaning",
        "carpet": "Carpet Cleaning",
        "re_clean": "Re-Clean $0",
        "team_review": {
          "office": "Office cleaning is quoted by the team.",
          "carpet": "Carpet cleaning is quoted by the team.",
          "re_clean": "Re-cleans are arranged by the team.",
          "one_time": "The service scope needs team review.",
          "maid": "The service scope needs team review.",
          "condo": "The service scope needs team review.",
          "apartment": "The service scope needs team review.",
          "eco_friendly": "Product and service requirements need team review."
        }
      }
    },
    "frequency": {
      "type": "string",
      "enum": [
        "one_time",
        "weekly",
        "biweekly",
        "every_3_weeks",
        "every_4_weeks"
      ],
      "default": "one_time",
      "x-labels": {
        "one_time": "One-time",
        "weekly": "Weekly",
        "biweekly": "Bi-weekly",
        "every_3_weeks": "Every 3 weeks",
        "every_4_weeks": "Every 4 weeks"
      },
      "x-bookingkoala": {
        "one_time": {
          "id": "freq_1",
          "summary": "OT"
        },
        "weekly": {
          "id": "freq_11",
          "summary": "W"
        },
        "biweekly": {
          "id": "freq_10",
          "summary": "2W"
        },
        "every_3_weeks": {
          "id": "freq_17",
          "summary": "3W"
        },
        "every_4_weeks": {
          "id": "freq_9",
          "summary": "4W"
        }
      }
    },
    "bedrooms": {
      "type": "integer",
      "minimum": 0,
      "maximum": 100,
      "description": "0 or 1 selects Studio / 1; 2–7 use the corresponding option. Larger homes go to the team."
    },
    "bathrooms": {
      "type": "number",
      "minimum": 0,
      "maximum": 100,
      "multipleOf": 0.5,
      "description": "Bathrooms and half-bathrooms: rounded up to the next whole form option, as in the staff quote tool. More than 7 goes to the team."
    },
    "square_feet": {
      "type": "integer",
      "minimum": 1,
      "maximum": 1000000,
      "x-bookingkoala": [
        {
          "min": 1,
          "max": 599,
          "label": "0001 - 0599 Sq Ft"
        },
        {
          "min": 600,
          "max": 1199,
          "label": "0600 - 1199 Sq Ft"
        },
        {
          "min": 1200,
          "max": 1999,
          "label": "1200 - 1999 Sq Ft"
        },
        {
          "min": 2000,
          "max": 2499,
          "label": "2000 - 2499 Sq Ft"
        },
        {
          "min": 2500,
          "max": 2999,
          "label": "2500 - 2999 Sq Ft"
        },
        {
          "min": 3000,
          "max": 3499,
          "label": "3000 - 3499 Sq Ft"
        },
        {
          "min": 3500,
          "max": 3999,
          "label": "3500 - 3999 Sq Ft"
        },
        {
          "min": 4000,
          "max": 4499,
          "label": "4000 - 4499 Sq Ft"
        },
        {
          "min": 4500,
          "max": 4999,
          "label": "4500 - 4999 Sq Ft"
        },
        {
          "min": 5000,
          "max": 5499,
          "label": "5000 - 5499 Sq Ft"
        },
        {
          "min": 5500,
          "max": 5999,
          "label": "5500 - 5999 Sq Ft"
        },
        {
          "min": 6000,
          "max": 7000,
          "label": "6000 - 7000 Sq Ft"
        }
      ]
    },
    "extras": {
      "type": "array",
      "maxItems": 12,
      "uniqueItems": true,
      "items": {
        "type": "string",
        "enum": [
          "inside_oven",
          "inside_fridge",
          "inside_cabinets",
          "interior_walls",
          "hand_wiped_baseboards",
          "dishes",
          "laundry_and_folding",
          "finished_basement",
          "pet_hair",
          "windows_and_tracks",
          "extra_appliances",
          "extra_cupboards",
          "heavy_duty",
          "window_blinds",
          "additional_hours_recurring",
          "additional_30_minutes",
          "additional_hours",
          "miscellaneous"
        ]
      },
      "x-bookingkoala": {
        "automatic": {
          "inside_oven": {
            "prefix": "Inside Oven",
            "size_banded": false
          },
          "inside_fridge": {
            "prefix": "Inside Fridge",
            "size_banded": false
          },
          "inside_cabinets": {
            "prefix": "Inside Cabinets",
            "size_banded": true
          },
          "interior_walls": {
            "prefix": "Clean Interior Walls",
            "size_banded": true
          },
          "hand_wiped_baseboards": {
            "prefix": "Hand Wipe Baseboards",
            "size_banded": true
          },
          "dishes": {
            "prefix": "Handwash Dishes",
            "size_banded": false
          },
          "laundry_and_folding": {
            "prefix": "Laundry & Folding",
            "size_banded": false
          },
          "finished_basement": {
            "prefix": "Finished Basement",
            "size_banded": false
          },
          "pet_hair": {
            "prefix": "Pet Hair Fee",
            "size_banded": true
          },
          "heavy_duty": {
            "prefix": "Heavy Duty",
            "size_banded": true
          }
        },
        "team_review": {
          "windows_and_tracks": "Interior windows are priced per room.",
          "window_blinds": "Window blinds need a window count.",
          "extra_appliances": "Extra appliances need a description.",
          "extra_cupboards": "Extra cupboards need a count.",
          "additional_hours_recurring": "Additional recurring time needs team review.",
          "additional_30_minutes": "Additional time needs team review.",
          "additional_hours": "Additional time needs team review.",
          "miscellaneous": "Miscellaneous services need a description."
        },
        "quantity_note": "Laundry and folding selects one default load, as in the staff quote tool. Additional loads need team review.",
        "size_note": "Size-banded extras are resolved by prefix and explicit range on the currently rendered form. Missing or ambiguous tiers need team review."
      }
    },
    "client": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "name": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100
        },
        "email": {
          "type": "string",
          "minLength": 1,
          "maxLength": 254,
          "format": "email"
        },
        "phone": {
          "type": "string",
          "minLength": 1,
          "maxLength": 30
        }
      },
      "required": [
        "name",
        "email"
      ]
    },
    "agent": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "reply_email": {
          "type": "string",
          "minLength": 1,
          "maxLength": 254,
          "format": "email"
        },
        "name": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100
        },
        "operator": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100
        },
        "url": {
          "type": "string",
          "minLength": 1,
          "maxLength": 500,
          "format": "uri"
        }
      },
      "required": [
        "reply_email"
      ]
    },
    "consent": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "client_authorized": {
          "type": "boolean",
          "const": true
        }
      },
      "required": [
        "client_authorized"
      ]
    },
    "address": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "unit": {
          "type": "string",
          "minLength": 1,
          "maxLength": 80
        },
        "street": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200
        },
        "city": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100
        },
        "province": {
          "type": "string",
          "enum": [
            "ON",
            "BC"
          ]
        }
      },
      "required": []
    },
    "notes": {
      "type": "string",
      "minLength": 1,
      "maxLength": 2000
    },
    "access_notes": {
      "type": "string",
      "minLength": 1,
      "maxLength": 1000
    },
    "parking_note": {
      "type": "string",
      "minLength": 1,
      "maxLength": 500
    },
    "pets_note": {
      "type": "string",
      "minLength": 1,
      "maxLength": 500
    },
    "preferred_dates": {
      "type": "array",
      "maxItems": 5,
      "uniqueItems": true,
      "items": {
        "type": "string",
        "minLength": 1,
        "maxLength": 80
      }
    },
    "preferred_times": {
      "type": "array",
      "maxItems": 5,
      "uniqueItems": true,
      "items": {
        "type": "string",
        "minLength": 1,
        "maxLength": 80
      }
    }
  },
  "required": [
    "postal_code",
    "service",
    "square_feet",
    "client",
    "agent",
    "consent"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://cleaninghive.ca/api/booking-fields.json",
  "title": "Cleaning Hive quote request",
  "description": "Request a quote with the client’s permission. Prices come from the staff booking form. This request does not book an appointment.",
  "allOf": [
    {
      "if": {
        "properties": {
          "service": {
            "enum": [
              "office"
            ]
          }
        },
        "required": [
          "service"
        ]
      },
      "else": {
        "required": [
          "bedrooms",
          "bathrooms"
        ]
      }
    }
  ]
}
