{
  "openapi": "3.1.0",
  "info": {
    "title": "Unwinter property request and quote API",
    "version": "1.0.0",
    "description": "Creates property assessment requests and enquiries. A saved request is not a booking. Payment actions require a valid approved private quote and explicit buyer consent.",
    "contact": {
      "name": "Unwinter customer enquiries",
      "email": "support@unwinter.ca"
    }
  },
  "servers": [
    {
      "url": "https://mx1.hellabit.com/unwinter"
    }
  ],
  "paths": {
    "/api/config": {
      "get": {
        "operationId": "readServiceConfiguration",
        "summary": "Read current intake and payment availability",
        "responses": {
          "200": {
            "description": "Current result. Read all status fields.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "intakeEnabled": {
                      "type": "boolean"
                    },
                    "contactEnabled": {
                      "type": "boolean"
                    },
                    "paymentEnabled": {
                      "type": "boolean"
                    },
                    "operatorAssigned": {
                      "type": "boolean"
                    },
                    "operatorDeliveryEnabled": {
                      "type": "boolean"
                    },
                    "paypalEnvironment": {
                      "type": "string"
                    },
                    "live": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "The operation was not completed as requested. Inspect the returned error; do not blindly repeat a payment mutation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/requests": {
      "post": {
        "operationId": "requestPropertyAssessment",
        "summary": "Submit an explicitly authorized property assessment request; no booking or charge",
        "x-human-consent-required": true,
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Production mutations require the approved website Origin; non-browser clients must send it explicitly. This does not replace human consent.",
            "schema": {
              "type": "string",
              "enum": [
                "https://unwinter.ca",
                "https://www.unwinter.ca"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "email",
                  "propertyType",
                  "postalCode",
                  "address",
                  "service",
                  "consent"
                ],
                "additionalProperties": false,
                "properties": {
                  "submissionId": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Generate once per approved submission intent. Reuse with an identical payload after an uncertain response; never reuse for changed data."
                  },
                  "name": {
                    "type": "string",
                    "description": "Authorized contact name",
                    "maxLength": 120,
                    "minLength": 2
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "maxLength": 254
                  },
                  "phone": {
                    "type": "string",
                    "description": "Optional telephone; when supplied, 10–15 digits",
                    "maxLength": 40
                  },
                  "organization": {
                    "type": "string",
                    "description": "Business or property name",
                    "maxLength": 180
                  },
                  "propertyType": {
                    "type": "string",
                    "description": "Property category, supplied by the customer",
                    "maxLength": 80
                  },
                  "postalCode": {
                    "type": "string",
                    "pattern": "^[A-Za-z][0-9][A-Za-z][ -]?[0-9][A-Za-z][0-9]$"
                  },
                  "address": {
                    "type": "string",
                    "description": "Property street address and city",
                    "maxLength": 300,
                    "minLength": 5
                  },
                  "service": {
                    "type": "string",
                    "description": "Requested services to assess; not a confirmed scope",
                    "maxLength": 500
                  },
                  "criticalTimes": {
                    "type": "string",
                    "description": "Relevant access or operating times",
                    "maxLength": 300
                  },
                  "areaEstimate": {
                    "type": "string",
                    "description": "Approximate service area, if known",
                    "maxLength": 300
                  },
                  "notes": {
                    "type": "string",
                    "description": "Relevant property notes; no security credentials or unrelated sensitive data",
                    "maxLength": 3000
                  },
                  "consent": {
                    "type": "boolean",
                    "const": true,
                    "description": "Must reflect explicit human authorization and privacy consent for this exact property request. Do not infer."
                  },
                  "photos": {
                    "type": "array",
                    "maxItems": 3,
                    "description": "Optional customer-authorized property images. Max2MiB each and4MiB combined.",
                    "items": {
                      "type": "object",
                      "required": [
                        "type",
                        "data"
                      ],
                      "properties": {
                        "name": {
                          "type": "string",
                          "description": "Image filename",
                          "maxLength": 255
                        },
                        "type": {
                          "type": "string",
                          "enum": [
                            "image/jpeg",
                            "image/png",
                            "image/webp"
                          ]
                        },
                        "data": {
                          "type": "string",
                          "contentEncoding": "base64",
                          "description": "Image bytes encoded as base64, without a data-URL prefix."
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current result. Read all status fields.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "message"
                  ],
                  "properties": {
                    "requestId": {
                      "type": "string",
                      "description": "Saved property request reference"
                    },
                    "contactId": {
                      "type": "string",
                      "description": "Saved enquiry reference"
                    },
                    "status": {
                      "type": "string",
                      "description": "Current server-recorded state; not a booking confirmation"
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable result; reproduce its meaning accurately"
                    },
                    "notificationStatus": {
                      "type": "string",
                      "enum": [
                        "queued",
                        "not_active"
                      ],
                      "description": "Owner notification only. This is not operator dispatch or delivery proof."
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Current result. Read all status fields.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "message"
                  ],
                  "properties": {
                    "requestId": {
                      "type": "string",
                      "description": "Saved property request reference"
                    },
                    "contactId": {
                      "type": "string",
                      "description": "Saved enquiry reference"
                    },
                    "status": {
                      "type": "string",
                      "description": "Current server-recorded state; not a booking confirmation"
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable result; reproduce its meaning accurately"
                    },
                    "notificationStatus": {
                      "type": "string",
                      "enum": [
                        "queued",
                        "not_active"
                      ],
                      "description": "Owner notification only. This is not operator dispatch or delivery proof."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The operation was not completed as requested. Inspect the returned error; do not blindly repeat a payment mutation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "The operation was not completed as requested. Inspect the returned error; do not blindly repeat a payment mutation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "The operation was not completed as requested. Inspect the returned error; do not blindly repeat a payment mutation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/contact": {
      "post": {
        "operationId": "submitCustomerEnquiry",
        "summary": "Save an authorized service or privacy enquiry",
        "x-human-consent-required": true,
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Production mutations require the approved website Origin; non-browser clients must send it explicitly. This does not replace human consent.",
            "schema": {
              "type": "string",
              "enum": [
                "https://unwinter.ca",
                "https://www.unwinter.ca"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "email",
                  "message",
                  "type"
                ],
                "additionalProperties": false,
                "properties": {
                  "submissionId": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Generate once per approved submission intent. Reuse with an identical payload after an uncertain response; never reuse for changed data."
                  },
                  "name": {
                    "type": "string",
                    "description": "Authorized contact name",
                    "maxLength": 120,
                    "minLength": 2
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "maxLength": 254
                  },
                  "requestId": {
                    "type": "string",
                    "maxLength": 40,
                    "pattern": "^(?:(?:UW|UWQ|UWC|SG|SGQ|SGC)-[A-Z0-9]{6,32})?$"
                  },
                  "message": {
                    "type": "string",
                    "minLength": 20,
                    "maxLength": 3000
                  },
                  "type": {
                    "type": "string",
                    "enum": [
                      "privacy",
                      "service"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current result. Read all status fields.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "message"
                  ],
                  "properties": {
                    "requestId": {
                      "type": "string",
                      "description": "Saved property request reference"
                    },
                    "contactId": {
                      "type": "string",
                      "description": "Saved enquiry reference"
                    },
                    "status": {
                      "type": "string",
                      "description": "Current server-recorded state; not a booking confirmation"
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable result; reproduce its meaning accurately"
                    },
                    "notificationStatus": {
                      "type": "string",
                      "enum": [
                        "queued",
                        "not_active"
                      ],
                      "description": "Owner notification only. This is not operator dispatch or delivery proof."
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Current result. Read all status fields.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "message"
                  ],
                  "properties": {
                    "requestId": {
                      "type": "string",
                      "description": "Saved property request reference"
                    },
                    "contactId": {
                      "type": "string",
                      "description": "Saved enquiry reference"
                    },
                    "status": {
                      "type": "string",
                      "description": "Current server-recorded state; not a booking confirmation"
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable result; reproduce its meaning accurately"
                    },
                    "notificationStatus": {
                      "type": "string",
                      "enum": [
                        "queued",
                        "not_active"
                      ],
                      "description": "Owner notification only. This is not operator dispatch or delivery proof."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The operation was not completed as requested. Inspect the returned error; do not blindly repeat a payment mutation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "The operation was not completed as requested. Inspect the returned error; do not blindly repeat a payment mutation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "The operation was not completed as requested. Inspect the returned error; do not blindly repeat a payment mutation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/quotes/{token}": {
      "get": {
        "operationId": "readPrivateQuote",
        "summary": "Read a private quote provided by the customer",
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "description": "Private quote token supplied by the customer. Keep it private; never discover or guess tokens.",
            "schema": {
              "type": "string",
              "pattern": "^[a-f0-9]{64}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current result. Read all status fields.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "reference",
                    "scope",
                    "totalMinor",
                    "currency",
                    "termsVersion",
                    "payable",
                    "paymentEnabled",
                    "status"
                  ],
                  "properties": {
                    "reference": {
                      "type": "string",
                      "description": "Quote reference"
                    },
                    "scope": {
                      "type": "string",
                      "description": "Exact written property scope"
                    },
                    "operatorName": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Field-service operator for this quote. Null means incomplete and not payable."
                    },
                    "terms": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Readable property-specific service and cancellation terms. Null means incomplete and not payable."
                    },
                    "taxNote": {
                      "type": "string",
                      "description": "Exact tax treatment"
                    },
                    "paymentType": {
                      "type": "string",
                      "enum": [
                        "deposit",
                        "full_amount"
                      ]
                    },
                    "totalMinor": {
                      "type": "integer",
                      "minimum": 1,
                      "description": "Amount in currency minor units; CAD100 means CA$1.00."
                    },
                    "currency": {
                      "type": "string",
                      "enum": [
                        "CAD"
                      ]
                    },
                    "expiresAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "termsVersion": {
                      "type": "string",
                      "description": "Exact terms version required when approving an order"
                    },
                    "payable": {
                      "type": "boolean"
                    },
                    "paymentEnabled": {
                      "type": "boolean"
                    },
                    "status": {
                      "type": "string",
                      "description": "Current quote state"
                    },
                    "paypalEnvironment": {
                      "type": "string",
                      "enum": [
                        "sandbox"
                      ],
                      "description": "Current payment integration is sandbox. A sandbox result does not take live money."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "The operation was not completed as requested. Inspect the returned error; do not blindly repeat a payment mutation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/quotes/{token}/orders": {
      "post": {
        "operationId": "prepareApprovedQuotePayment",
        "summary": "Create a PayPal approval link after explicit approval of the exact quote and terms",
        "x-human-consent-required": true,
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "description": "Private quote token supplied by the customer. Keep it private; never discover or guess tokens.",
            "schema": {
              "type": "string",
              "pattern": "^[a-f0-9]{64}$"
            }
          },
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Production mutations require the approved website Origin; non-browser clients must send it explicitly. This does not replace human consent.",
            "schema": {
              "type": "string",
              "enum": [
                "https://unwinter.ca",
                "https://www.unwinter.ca"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "acceptedTerms",
                  "termsVersion"
                ],
                "properties": {
                  "acceptedTerms": {
                    "type": "boolean",
                    "const": true,
                    "description": "Explicit customer approval of the displayed current quote, amount and terms."
                  },
                  "termsVersion": {
                    "type": "string",
                    "description": "Version retrieved from the current quote"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current result. Read all status fields.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "orderId": {
                      "type": "string"
                    },
                    "approveUrl": {
                      "type": "string",
                      "format": "uri"
                    },
                    "paypalEnvironment": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The operation was not completed as requested. Inspect the returned error; do not blindly repeat a payment mutation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "The operation was not completed as requested. Inspect the returned error; do not blindly repeat a payment mutation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "The operation was not completed as requested. Inspect the returned error; do not blindly repeat a payment mutation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/quotes/{token}/capture": {
      "post": {
        "operationId": "verifyBuyerApprovedPayment",
        "summary": "Capture and verify a PayPal order after PayPal buyer approval; never infer approval",
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "description": "Private quote token supplied by the customer. Keep it private; never discover or guess tokens.",
            "schema": {
              "type": "string",
              "pattern": "^[a-f0-9]{64}$"
            }
          },
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Production mutations require the approved website Origin; non-browser clients must send it explicitly. This does not replace human consent.",
            "schema": {
              "type": "string",
              "enum": [
                "https://unwinter.ca",
                "https://www.unwinter.ca"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "orderId"
                ],
                "properties": {
                  "orderId": {
                    "type": "string",
                    "pattern": "^[A-Z0-9]{8,40}$"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current result. Read all status fields.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "reference": {
                      "type": "string"
                    },
                    "captureId": {
                      "type": "string"
                    },
                    "paypalEnvironment": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "The operation was not completed as requested. Inspect the returned error; do not blindly repeat a payment mutation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "The operation was not completed as requested. Inspect the returned error; do not blindly repeat a payment mutation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
