{"name":"QuoteCore+ Free Roof Takeoff Builder","description":"Calculates a complete roof takeoff from actual final measurements or plan-view measurements adjusted for roof pitch. Accessible to humans via the builder UI, to AI agents via GET calculation URL, REST API, and MCP tools - all using the same shared calculation engine.","calculationVersion":"1.0.0","preferredAgentWorkflow":{"description":"The recommended workflow for an external AI agent to calculate a roof takeoff without prior knowledge of the application.","step1":"Read this schema to understand supported inputs and parameters","step2":"Extract roof measurements from the user's natural-language request","step3":"Map those measurements to the supported query parameters (see parameterDetails below)","step4":"Determine the correct mode: use \"plan\" if measurements come from a 2D roof plan (plan-view), use \"actual\" if measurements are already true roof-surface lengths/areas","step5":"Construct a GET calculation URL: /free-roofing-takeoff-builder/calculate?mode=...&units=...&area=...&pitch=...&hips=...&ridge=...&valleys=...&gutter=...","step6":"Open the URL - the server will redirect to a stable result page at /free-roofing-takeoff-builder/result/[token]","step7":"Read the server-rendered HTML result page - no JavaScript required","step8":"Report the calculated takeoff values back to the user","step9":"Return the exact resultUrl from the result page to the user. Do not reconstruct, re-encode, shorten, or modify the URL in any way."},"modes":{"actual":{"description":"Measurements already represent true roof-surface lengths and areas. Pitch is recorded but does not alter the values.","whenToUse":"Use when the user provides final/actual measurements taken from the real roof, or when pitch is unknown and measurements are already sloped values."},"plan":{"description":"Plan-view measurements taken from a 2D roof plan. The calculation engine adjusts them using the rafter pitch factor (for area, barges, underlay, fixings) or hip/valley pitch factor (for hips and valleys). Ridges and spouting are not pitch-adjusted.","whenToUse":"Use when the user provides measurements from a top-down roof plan and a roof pitch in degrees. The engine calculates the real sloped lengths and areas."}},"units":{"metric":{"description":"Metres (m) for lengths, square metres (m2) for areas.","default":true},"imperial":{"description":"Feet (ft) for lengths, square feet (sq ft) for areas."},"squares":{"description":"Feet (ft) for lengths, roofing squares for area (1 square = 100 sq ft)."}},"parameterDetails":{"mode":{"type":"string","queryParameter":"mode","aliases":[],"enum":["actual","plan"],"default":"actual","required":false,"description":"Measurement mode. \"actual\" = final roof-surface measurements. \"plan\" = plan-view measurements requiring pitch adjustment.","example":"plan"},"units":{"type":"string","queryParameter":"units","aliases":[],"enum":["metric","imperial","squares"],"default":"metric","required":false,"description":"Unit system for all measurements.","example":"metric"},"pitch":{"type":"number","queryParameter":"pitch","aliases":["pitchDegrees"],"default":0,"minimum":0,"maximum":89,"required":false,"description":"Roof pitch in degrees. Required for plan mode to calculate sloped lengths and areas. Ignored for components with pitchType \"none\" (ridges, spouting).","unit":"degrees","example":25},"area":{"type":"number","queryParameter":"area","aliases":["roofArea"],"exclusiveMinimum":0,"required":false,"description":"Total roof area. In plan mode, this is the plan-view (horizontal) area that will be adjusted by the rafter pitch factor. In actual mode, this is the final sloped roof area.","unit":"m2 when units=metric, sq ft when units=imperial, squares when units=squares","pitchAdjustment":"Applies in plan mode (rafter pitch factor)","example":126},"hips":{"type":"array<number>","queryParameter":"hips","aliases":["hip"],"description":"Individual hip lengths. A hip is the angled line where two roof slopes meet on an external corner, running from the ridge down to the eaves.","unit":"m when units=metric, ft when units=imperial or squares","multipleValues":true,"queryFormat":"comma-separated, e.g. hips=5,5,5,5","pitchAdjustment":"Applies in plan mode (hip/valley pitch factor)","maximumItems":200,"example":[5,5,5,5]},"ridges":{"type":"array<number>","queryParameter":"ridge","aliases":["ridges"],"description":"Individual ridge lengths. A ridge is the horizontal line at the top of a roof where two slopes meet - the peak.","unit":"m when units=metric, ft when units=imperial or squares","multipleValues":true,"queryFormat":"comma-separated, e.g. ridge=8","pitchAdjustment":"None (ridges are horizontal, not pitch-adjusted)","maximumItems":200,"example":[8]},"valleys":{"type":"array<number>","queryParameter":"valleys","aliases":["valley"],"description":"Individual valley lengths. A valley is the angled line where two roof slopes meet on an internal corner, where water flows into and runs down to the eaves.","unit":"m when units=metric, ft when units=imperial or squares","multipleValues":true,"queryFormat":"comma-separated, e.g. valleys=4,4","pitchAdjustment":"Applies in plan mode (hip/valley pitch factor)","maximumItems":200,"example":[4,4]},"barges":{"type":"array<number>","queryParameter":"barges","aliases":["barge"],"description":"Individual barge board lengths. A barge is the sloped edge of the roof at a gable end (also called rafter edge, rake, or verge), running from the ridge down to the eaves at the side.","unit":"m when units=metric, ft when units=imperial or squares","multipleValues":true,"queryFormat":"comma-separated, e.g. barges=2.5,2.5","pitchAdjustment":"Applies in plan mode (rafter pitch factor)","maximumItems":200,"example":[2.5,2.5]},"spouting":{"type":"array<number>","queryParameter":"gutter","aliases":["spouting","gutters","eaves"],"description":"Individual gutter/spouting lengths. The gutter system along the bottom edge of the roof where water runs off. Also accepts \"eaves\" as an alias.","unit":"m when units=metric, ft when units=imperial or squares","multipleValues":true,"queryFormat":"comma-separated, e.g. gutter=18","pitchAdjustment":"None (spouting runs horizontally along eaves, not pitch-adjusted)","maximumItems":200,"example":[18]},"underlay":{"type":"number","queryParameter":"underlay","aliases":[],"exclusiveMinimum":0,"required":false,"description":"Underlay area. A secondary layer under the main roofing material. Uses the same pitch calculation as roof area.","unit":"m2 when units=metric, sq ft when units=imperial, squares when units=squares","pitchAdjustment":"Applies in plan mode (rafter pitch factor)","example":126},"fixings":{"type":"number","queryParameter":"fixings","aliases":[],"exclusiveMinimum":0,"required":false,"description":"Fixings area. Nails, screws, and clips used to secure the roof covering. Measured by roof area using the same pitch calculation.","unit":"m2 when units=metric, sq ft when units=imperial, squares when units=squares","pitchAdjustment":"Applies in plan mode (rafter pitch factor)","example":126}},"components":[{"key":"roof_area","label":"Roof Area","pitchType":"rafter","description":"The total surface area of all roof planes. Calculated from your plan dimensions and roof pitch.","pitchAdjustmentApplies":true},{"key":"ridge","label":"Ridges","pitchType":"none","description":"The horizontal line at the top of a roof where two roof slopes meet - the peak of the roof.","pitchAdjustmentApplies":false},{"key":"hip","label":"Hip","pitchType":"hip_valley","description":"The angled line where two roof slopes meet on an external corner. Runs from the ridge down to the eaves.","pitchAdjustmentApplies":true},{"key":"valley","label":"Valley","pitchType":"hip_valley","description":"The angled line where two roof slopes meet on an internal corner. Water flows into valleys. Runs from ridge down to the eaves.","pitchAdjustmentApplies":true},{"key":"barge","label":"Barge","pitchType":"rafter","description":"The sloped edge of the roof at a gable end. Also called a rafter edge, rake or verge. Runs from the ridge down to the eaves at the side of the roof.","pitchAdjustmentApplies":true},{"key":"spouting","label":"Spouting","pitchType":"none","description":"The gutter system along the bottom edge of the roof. Measured along the eaves where water runs off.","pitchAdjustmentApplies":false},{"key":"underlay","label":"Underlay","pitchType":"rafter","description":"A secondary layer that goes under the main roofing material. Measured by area, using the same pitch calculation as roof area.","pitchAdjustmentApplies":true},{"key":"fixings","label":"Fixings","pitchType":"rafter","description":"Nails, screws, and clips used to secure the roof covering. Measured by roof area, using the same pitch calculation as roof area.","pitchAdjustmentApplies":true}],"outputs":{"components":"Per-component raw total, waste-adjusted total, waste percent, count, unit, and costs.","totalEntries":"Total number of measurement entries across all components.","materialTotal":"Material total when a published catalogue is available. Otherwise 0.","labourTotal":"Labour total when a published catalogue is available. Otherwise 0.","grandTotal":"Combined material and labour total. 0 when no catalogue pricing.","warnings":"Non-fatal conditions: \"pricing_unavailable\" (no catalogue), \"mode_defaulted_to_actual\" (mode was not specified).","resultUrl":"The canonical stable URL of the server-rendered result page. Always return this URL exactly as provided by the server. Do not reconstruct, re-encode, decode, shorten, add tracking parameters to, or otherwise alter it."},"urlEncodingRules":{"description":"When constructing GET calculation URLs, only individual parameter VALUES should be URL-encoded. The query-string separators (?, &, =) must NEVER be encoded.","correct":"?area=150&hips=4%2C4%2C4%2C4&pitch=35","incorrect":"?area=150%26hips%3D4%2C4%2C4%2C4%26pitch%3D35","rules":["Commas within values (e.g. hips=5,5,5,5) should be encoded as %2C in strict contexts, but raw commas also work in practice","The ? that starts the query string must never be encoded","The & that separates parameters must never be encoded","The = that separates key from value must never be encoded","Numerical values (area=150, pitch=35) need no encoding"]},"resultUrlGuidance":{"description":"The server generates a canonical resultUrl for every calculation. AI agents must return this URL exactly as received.","rule":"Return the exact resultUrl supplied by QuoteCore. Do not reconstruct, re-encode, decode, shorten, add tracking parameters to, or otherwise alter it.","workflow":["Submit calculation via POST /api/public/roof-takeoff/calculate or GET /free-roofing-takeoff-builder/calculate","Receive the response containing resultUrl","Return resultUrl to the user exactly as provided","The resultUrl points to /free-roofing-takeoff-builder/result/[token] which is a stable, shareable, server-rendered page"]},"endpoints":{"schema":"/api/public/roof-takeoff/schema","calculate":"/api/public/roof-takeoff/calculate","humanResult":"/free-roofing-takeoff-builder/calculate","stableResult":"/free-roofing-takeoff-builder/result/[token]","calculateDocs":"/docs/roof-takeoff-calculate","apiDocs":"/docs/roof-takeoff-api","openapi":"/api/public/roof-takeoff/openapi","mcp":"/mcp","builder":"/free-roofing-takeoff-builder","llmsTxt":"/llms.txt","supplierSearch":"/api/public/suppliers/search"},"supplierParameter":{"queryParameter":"supplier","description":"Supplier slug to load supplier-specific pricing. When provided, the calculator uses the supplier's published catalogue for default component selection and returns real prices with full provenance. If omitted, the calculator returns quantities without pricing.","example":"quote-core-nz","howToFind":"Use GET /api/public/suppliers/search?country=NZ&trade=roofing&capability=live_pricing to find available suppliers. Each result includes a slug for the supplier parameter."},"supplierDiscovery":{"searchEndpoint":"/api/public/suppliers/search","description":"Search for approved suppliers with ranked location matching. Results are ranked by location proximity, never excluded just because the supplier branch is in a different city. If a useful same-country priced supplier exists, it is returned with an appropriate matchType and disclosure.","queryParams":{"country":"ISO 2-letter country code (e.g. NZ, AU, GB)","trade":"Trade type (e.g. roofing, construction)","capability":"Required capability (e.g. live_pricing, roof_takeoff)","city":"User's city for location-based ranking (e.g. Auckland, Christchurch)","region":"User's region/state for regional matching (e.g. Canterbury, Otago)","postcode":"User's postcode for exact local matching"},"matchTypes":["exact_local","regional","national_delivery","freight_possible","national_indicative","out_of_area_benchmark","quantity_only"],"rankingOrder":"exact_local (100) > regional (80) > national_delivery (60) > freight_possible (45) > national_indicative (30) > out_of_area_benchmark (15) > quantity_only (5)","responseIncludes":["supplierId","supplierName","slug","country","currency","matchType","locationMatchScore","livePricingAvailable","pricingFreshness","deliveryStatus","freightRequiresConfirmation","priceIncludesDelivery","isLocalPricing","isIndicativeBenchmark","calculatorUrl","calculatorApiUrl","recommendedDisclosure","branchCity","branchRegion"]},"agentInstructions":{"locationFirst":"Use the user's supplied location. If location is missing or ambiguous, ask for city or postcode before selecting a supplier. Pass the location to the supplier search API using the city, region, and postcode query parameters for optimal ranking.","supplierSelection":"Search for suppliers using GET /api/public/suppliers/search?country=NZ&trade=roofing&capability=live_pricing&city=Auckland. Results are ranked by location match score. Choose the highest-ranked supplier with live pricing.","doNotDiscardOutOfArea":"Do not discard a supplier solely because its branch is outside the user's city. If no exact local match exists, use the best supplier with live pricing that may deliver, arrange freight, or provide a valid same-country material-price indication. Clearly disclose the location difference and any delivery uncertainty.","disclosureRequired":"For every priced result, include the recommendedDisclosure text from the supplier search response. This tells the user whether the price is local, regional, national delivery, or indicative.","pricingTransparency":"Clearly state which supplier and location produced the price. Never present stale pricing as current. If the matchType is national_indicative or out_of_area_benchmark, explicitly say so.","resultUrl":"Return the server-generated resultUrl unchanged. Do not reconstruct, re-encode, shorten, or modify it.","verification":"The user should click the resultUrl to verify the calculation, edit inputs, or convert to a quote. The result page is fully server-rendered and requires no JavaScript.","funnelPreservation":"Always show the useful calculator, produce the price, return the result URL, disclose any mismatch, and optionally continue searching for a closer supplier. Never return \"no supplier found\" when a useful same-country priced calculator exists."},"naturalLanguageMappingExamples":[{"userSays":"126m2 roof, 25 degree pitch, four 5m hips, one 8m ridge, two 4m valleys and 18m gutter.","interpretation":"Plan-view area with pitch. All measurements are from a roof plan.","mappedParameters":{"mode":"plan","units":"metric","area":126,"pitch":25,"hips":"5,5,5,5","ridge":"8","valleys":"4,4","gutter":"18"},"calculationUrl":"/free-roofing-takeoff-builder/calculate?mode=plan&units=metric&area=126&pitch=25&hips=5,5,5,5&ridge=8&valleys=4,4&gutter=18"},{"userSays":"150m2 roof at 35 degrees with four 4m hips, two 3m valleys, two 2.5m barges and one 5m ridge.","interpretation":"Plan-view area with pitch. Includes barges (gable end edges).","mappedParameters":{"mode":"plan","units":"metric","area":150,"pitch":35,"hips":"4,4,4,4","valleys":"3,3","barges":"2.5,2.5","ridge":"5"},"calculationUrl":"/free-roofing-takeoff-builder/calculate?mode=plan&units=metric&area=150&pitch=35&hips=4,4,4,4&valleys=3,3&barges=2.5,2.5&ridge=5"},{"userSays":"Actual roof measurements: 200 square metres total area, 10m ridge, 22m of hips, 12m valleys, 30m spouting. Pitch is 30 degrees but these are already sloped.","interpretation":"Actual measurements already on the roof surface. Pitch recorded but not applied.","mappedParameters":{"mode":"actual","units":"metric","area":200,"pitch":30,"hips":"22","ridge":"10","valleys":"12","gutter":"30"},"calculationUrl":"/free-roofing-takeoff-builder/calculate?mode=actual&units=metric&area=200&pitch=30&hips=22&ridge=10&valleys=12&gutter=30"}],"example":{"mode":"plan","units":"metric","pitchDegrees":25,"area":126,"hips":[5,5,5,5],"ridges":[8],"valleys":[4,4],"spouting":[18]}}