{
  "arazzo": "1.0.1",
  "info": {
    "title": "CleanedWeb deterministic property workflows",
    "summary": "Exact-count, bounded-search, and history workflows over maintained canonical property data.",
    "version": "2.0.0"
  },
  "sourceDescriptions": [
    {
      "name": "cleanedweb",
      "url": "https://cleanedweb.com/openapi.json",
      "type": "openapi"
    }
  ],
  "workflows": [
    {
      "workflowId": "exactPropertyCount",
      "summary": "Count matching properties without retrieving property records.",
      "description": "Use this workflow whenever the requested output is only a number. It is read-only, projection-bound, and consumes no delivery Units.",
      "inputs": {
        "$ref": "https://cleanedweb.com/openapi.json#/components/schemas/PropertyCountRequest"
      },
      "steps": [
        {
          "stepId": "listEntitledMarkets",
          "operationId": "listMarkets",
          "successCriteria": [{"condition": "$statusCode == 200"}],
          "outputs": {"markets": "$response.body#/markets"}
        },
        {
          "stepId": "countMatchingProperties",
          "operationId": "countProperties",
          "requestBody": {
            "contentType": "application/json",
            "payload": "$inputs"
          },
          "successCriteria": [{"condition": "$statusCode == 200"}],
          "outputs": {
            "total_matched": "$response.body#/total_matched",
            "cached": "$response.body#/cached",
            "resolved_query": "$response.body#/resolved_query",
            "snapshot": "$response.body#/snapshot"
          }
        }
      ],
      "outputs": {
        "total_matched": "$steps.countMatchingProperties.outputs.total_matched",
        "cached": "$steps.countMatchingProperties.outputs.cached",
        "resolved_query": "$steps.countMatchingProperties.outputs.resolved_query",
        "snapshot": "$steps.countMatchingProperties.outputs.snapshot"
      }
    },
    {
      "workflowId": "boundedPropertySearch",
      "summary": "List entitled markets and retrieve bounded rich property records.",
      "description": "Use only when property records are required. Precondition: fetch /v1/capabilities, require a supported contract and machine_access.enabled, and read current Unit costs and limits.",
      "inputs": {
        "type": "object",
        "required": ["market", "response_schema", "limit", "max_units", "idempotency_key"],
        "properties": {
          "market": {"type": "string", "pattern": "^[A-Z]{2,3}$"},
          "response_schema": {"const": "property-profile-v2"},
          "deal_type": {
            "type": "array",
            "items": {"enum": ["buy", "rent", "off_market"]},
            "uniqueItems": true
          },
          "limit": {"type": "integer", "minimum": 1},
          "max_units": {"type": "number", "minimum": 0},
          "idempotency_key": {"type": "string", "minLength": 1, "maxLength": 200}
        }
      },
      "steps": [
        {
          "stepId": "listEntitledMarkets",
          "operationId": "listMarkets",
          "successCriteria": [{"condition": "$statusCode == 200"}],
          "outputs": {"markets": "$response.body#/markets"}
        },
        {
          "stepId": "searchMaintainedProperties",
          "operationId": "searchProperties",
          "parameters": [
            {
              "name": "Idempotency-Key",
              "in": "header",
              "value": "$inputs.idempotency_key"
            }
          ],
          "requestBody": {
            "contentType": "application/json",
            "payload": {
              "market": "$inputs.market",
              "response_schema": "$inputs.response_schema",
              "deal_type": "$inputs.deal_type",
              "limit": "$inputs.limit",
              "max_units": "$inputs.max_units"
            }
          },
          "successCriteria": [
            {"condition": "$statusCode == 200"},
            {"condition": "$response.body#/truncated == false"}
          ],
          "outputs": {
            "results": "$response.body#/results",
            "snapshot": "$response.body#/snapshot",
            "usage": "$response.body#/usage"
          }
        }
      ],
      "outputs": {
        "results": "$steps.searchMaintainedProperties.outputs.results",
        "snapshot": "$steps.searchMaintainedProperties.outputs.snapshot",
        "usage": "$steps.searchMaintainedProperties.outputs.usage"
      }
    },
    {
      "workflowId": "readPropertyHistory",
      "summary": "Retrieve one canonical property and its finalized changes.",
      "inputs": {
        "type": "object",
        "required": ["property_entity_id"],
        "properties": {
          "property_entity_id": {"type": "string", "minLength": 1},
          "change_limit": {"type": "integer", "minimum": 1, "maximum": 200, "default": 50}
        }
      },
      "steps": [
        {
          "stepId": "readCanonicalProperty",
          "operationId": "getProperty",
          "parameters": [
            {
              "name": "property_entity_id",
              "in": "path",
              "value": "$inputs.property_entity_id"
            }
          ],
          "successCriteria": [{"condition": "$statusCode == 200"}],
          "outputs": {"property": "$response.body"}
        },
        {
          "stepId": "readFinalizedChanges",
          "operationId": "listPropertyChanges",
          "parameters": [
            {
              "name": "property_entity_id",
              "in": "path",
              "value": "$inputs.property_entity_id"
            },
            {"name": "limit", "in": "query", "value": "$inputs.change_limit"}
          ],
          "successCriteria": [{"condition": "$statusCode == 200"}],
          "outputs": {"changes": "$response.body#/changes"}
        }
      ],
      "outputs": {
        "property": "$steps.readCanonicalProperty.outputs.property",
        "changes": "$steps.readFinalizedChanges.outputs.changes"
      }
    }
  ]
}
