{"openapi":"3.1.0","info":{"title":"RoofLine360 API","version":"1.0.0","summary":"Roof measurements, 3D geometry, LiDAR scans and solar layouts for any US address.","description":"Send an address, get a measured roof. RoofLine360 rebuilds the roof from aerial LiDAR: slope areas, pitches, edge lengths, a material takeoff, GeoJSON geometry, the classified point cloud, four solar panel layouts with a typical-year production estimate, and the PDF report.\n\nA new roof takes from a few seconds (survey data already on hand) to a minute or two (first roof in an area). Create it with `POST /api/v1/roofs`, then poll `GET /api/v1/roofs/{id}` until `status` is `ready`.\n\nAuthenticate with `Authorization: Bearer rl360_...` (or `X-API-Key`). Errors are `{\"error\": {\"code\", \"message\"}}`."},"servers":[{"url":"https://roofline360.com","description":"Production"},{"url":"https://staging.roofline360.com","description":"Staging"},{"url":"http://127.0.0.1:8840","description":"Local app (app.py)"}],"security":[{"bearer":[]}],"tags":[{"name":"Roofs","description":"Build a roof model from an address and follow its status."},{"name":"Measurements","description":"Everything measured on a ready roof."},{"name":"Solar","description":"Panel layouts and production estimates."},{"name":"Account","description":"Your key's usage and API access."}],"paths":{"/api/v1/roofs":{"post":{"tags":["Roofs"],"operationId":"createRoof","summary":"Measure the roof at an address","description":"Looks the address up and starts the roof model, or returns the existing roof when this house was measured before (status `ready`, HTTP 200). A new build answers HTTP 202 with status `queued` or `building`. A new roof counts against your key's daily limit only when it builds successfully; failed builds are free, and builds in progress hold their place until they end.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoofRequest"},"examples":{"address":{"value":{"address":"10222 Wylde Point Ln, Missouri City, TX 77459"}},"coordinates":{"value":{"lat":29.477211,"lon":-95.514927}}}}}},"responses":{"200":{"description":"The roof was measured before and is ready.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Roof"}}}},"202":{"description":"The roof is being built; poll the `self` link.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Roof"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"get":{"tags":["Roofs"],"operationId":"listRoofs","summary":"List the roofs your key created","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"responses":{"200":{"description":"Newest first.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Roof"}}}}}}},"401":{"$ref":"#/components/responses/Error"}}}},"/api/v1/roofs/{id}":{"get":{"tags":["Roofs"],"operationId":"getRoof","summary":"Status and summary of a roof","parameters":[{"$ref":"#/components/parameters/RoofId"}],"responses":{"200":{"description":"The roof.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Roof"}}}},"404":{"$ref":"#/components/responses/Error"}}}},"/api/v1/roofs/{id}/measurements":{"get":{"tags":["Measurements"],"operationId":"getMeasurements","summary":"Areas, pitches, edge lengths and material takeoff","description":"The same numbers as the PDF report: surface, plan and footprint area, roofing squares, predominant pitch, edge lengths by type (eave, rake, ridge, hip, valley, step, slope break), the material takeoff and one row per slope.","parameters":[{"$ref":"#/components/parameters/RoofId"},{"name":"unit","in":"query","schema":{"type":"string","enum":["us","metric"],"default":"us"}},{"name":"waste","in":"query","description":"Waste allowance, percent.","schema":{"type":"number","minimum":0,"maximum":100,"default":10}},{"name":"bundles_per_square","in":"query","schema":{"type":"integer","minimum":1,"maximum":20,"default":3}}],"responses":{"200":{"description":"Measurements.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Measurements"}}}},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"}}}},"/api/v1/roofs/{id}/geometry":{"get":{"tags":["Measurements"],"operationId":"getGeometry","summary":"3D roof geometry as GeoJSON","description":"One FeatureCollection. `properties.layer` is `facet` (a roof slope, polygon), `step_side` (vertical wall between two roof levels), `edge` (line, `properties.kind` = eave, rake, ridge, hip, valley, step, slope break), `footprint` or `obstacle` (vent, chimney, skylight, panel). Coordinates carry z: elevation in metres.","parameters":[{"$ref":"#/components/parameters/RoofId"},{"name":"crs","in":"query","schema":{"type":"string","enum":["wgs84","utm"],"default":"wgs84"},"description":"`wgs84`: [lon, lat, z]. `utm`: metres of the house's UTM zone (`location.utm_epsg`)."}],"responses":{"200":{"description":"GeoJSON.","content":{"application/geo+json":{"schema":{"type":"object"}},"application/json":{"schema":{"type":"object"}}}},"409":{"$ref":"#/components/responses/Error"}}}},"/api/v1/roofs/{id}/scan":{"get":{"tags":["Measurements"],"operationId":"getScan","summary":"Classified LiDAR points of the house","description":"Column arrays x, y, z (metres, relative to `origin` in the house's UTM zone) and `cat`, an index into `categories` (ground, noise, low returns, elevated surroundings, other roof candidates, selected building). About 30,000 points, 1-2 MB.","parameters":[{"$ref":"#/components/parameters/RoofId"}],"responses":{"200":{"description":"Points.","content":{"application/json":{"schema":{"type":"object"}}}},"409":{"$ref":"#/components/responses/Error"}}}},"/api/v1/roofs/{id}/solar":{"get":{"tags":["Solar"],"operationId":"getSolar","summary":"Compare four panel layouts","description":"Places flush-mounted panels on every slope, avoiding obstacles and edges, in four layouts: `sun` (best-sun slopes only), `max` (fill every slope), `portrait`, `landscape`. For each: panel count, kW DC, annual and monthly kWh from a PVGIS typical year, specific yield and shade loss. Per slope: azimuth, tilt, open-sky yield and panels per layout.","parameters":[{"$ref":"#/components/parameters/RoofId"},{"name":"module","in":"query","description":"A key of `GET /api/v1/solar/modules`, or `custom` with length, width (m) and watts.","schema":{"type":"string","default":"res430"}},{"name":"length","in":"query","schema":{"type":"number"}},{"name":"width","in":"query","schema":{"type":"number"}},{"name":"watts","in":"query","schema":{"type":"number"}},{"name":"setback","in":"query","description":"Clearance from every slope edge, metres.","schema":{"type":"number","minimum":0,"maximum":3,"default":0.6}},{"name":"loss","in":"query","description":"System losses, percent.","schema":{"type":"number","minimum":0,"maximum":50,"default":14}},{"name":"exclude","in":"query","description":"Slope ids to leave without panels, comma-separated.","schema":{"type":"string","example":"3,7"}}],"responses":{"200":{"description":"Layouts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Solar"}}}},"400":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"}}}},"/api/v1/roofs/{id}/report.pdf":{"get":{"tags":["Measurements"],"operationId":"getReport","summary":"The customer-ready PDF report","description":"A multi-page PDF: cover, aerial view, roof plan with every edge dimensioned, pitch and area diagrams, slope schedule, material takeoff and the solar layout. Options as the measurements endpoint plus `solar_layout`, `solar_module`, `solar_setback`, `solar_loss`, `solar_excluded`.","parameters":[{"$ref":"#/components/parameters/RoofId"},{"name":"unit","in":"query","schema":{"type":"string","enum":["us","metric"],"default":"us"}},{"name":"waste","in":"query","schema":{"type":"number","default":10}},{"name":"bundles_per_square","in":"query","schema":{"type":"integer","default":3}},{"name":"solar_layout","in":"query","schema":{"type":"string","enum":["sun","max","portrait","landscape"],"default":"sun"}}],"responses":{"200":{"description":"PDF.","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"409":{"$ref":"#/components/responses/Error"}}}},"/api/v1/solar/modules":{"get":{"tags":["Solar"],"operationId":"listModules","summary":"Panel formats for the solar endpoint","responses":{"200":{"description":"Module catalog by key.","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/v1/usage":{"get":{"tags":["Account"],"operationId":"getUsage","summary":"Your key and today's successful builds","responses":{"200":{"description":"Usage.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"}}}},"401":{"$ref":"#/components/responses/Error"}}}},"/api/v1/access-requests":{"post":{"tags":["Account"],"operationId":"requestAccess","summary":"Ask for an API key","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","email"],"properties":{"name":{"type":"string"},"email":{"type":"string","format":"email"},"company":{"type":"string"},"use_case":{"type":"string"}}}}}},"responses":{"201":{"description":"Received."},"400":{"$ref":"#/components/responses/Error"}}}},"/mcp":{"post":{"tags":["Account"],"operationId":"mcp","summary":"Model Context Protocol server (Streamable HTTP)","description":"JSON-RPC 2.0 over HTTP for AI assistants: `initialize`, `tools/list`, `tools/call`. Tools: measure_roof, get_roof, get_roof_measurements, plan_solar, list_my_roofs, list_solar_modules. Same API key.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"JSON-RPC response."},"202":{"description":"Notification accepted."}}}}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"API key, `rl360_` followed by 40 hex characters."}},"parameters":{"RoofId":{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"h256139-3263493"}}},"responses":{"Error":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["unauthorized","invalid_parameter","not_found","not_ready","build_failed","rate_limited","not_available","server_error"]},"message":{"type":"string"}}}}},"RoofRequest":{"type":"object","description":"Either `address`, or `lat` and `lon`.","properties":{"address":{"type":"string","maxLength":200},"lat":{"type":"number"},"lon":{"type":"number"}}},"Roof":{"type":"object","properties":{"object":{"const":"roof"},"id":{"type":"string"},"status":{"type":"string","enum":["queued","building","ready","failed"]},"stage":{"type":["string","null"],"description":"While building: queued, downloading (survey data), processing (roof model)."},"message":{"type":["string","null"]},"address":{"type":"string"},"location":{"type":"object","properties":{"lat":{"type":"number"},"lon":{"type":"number"},"utm_epsg":{"type":"integer"}}},"created_at":{"type":"string"},"finished_at":{"type":["string","null"]},"elapsed_s":{"type":["number","null"]},"summary":{"type":["object","null"],"properties":{"slopes":{"type":"integer"},"roof_area_m2":{"type":"number"},"roof_area_ft2":{"type":"number"},"squares":{"type":"number"},"footprint_m2":{"type":"number"},"ridge_height_m":{"type":"number"}}},"links":{"type":"object","additionalProperties":{"type":"string"}}}},"Measurements":{"type":"object","properties":{"unit":{"type":"string"},"units":{"type":"object"},"roof":{"type":"object","properties":{"surface_area":{"type":"number"},"plan_area":{"type":"number"},"footprint_area":{"type":"number"},"squares":{"type":"number"},"ridge_height":{"type":"number"},"predominant_pitch":{"type":"string"},"slope_count":{"type":"integer"},"obstacle_count":{"type":"integer"}}},"edges":{"type":"object","properties":{"eave":{"type":"number"},"rake":{"type":"number"},"ridge":{"type":"number"},"hip":{"type":"number"},"valley":{"type":"number"},"step":{"type":"number"},"slope_break":{"type":"number"},"total":{"type":"number"}}},"materials":{"type":"object","properties":{"waste_percent":{"type":"number"},"bundles_per_square":{"type":"integer"},"coverage_area":{"type":"number"},"squares":{"type":"number"},"shingle_bundles":{"type":"integer"},"underlayment_area":{"type":"number"},"starter_drip_edge":{"type":"number"},"hip_ridge_cap":{"type":"number"},"valley_lining":{"type":"number"}}},"slopes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"pitch":{"type":"string"},"pitch_in_12":{"type":"number"},"slope_deg":{"type":"number"},"azimuth_deg":{"type":["number","null"]},"facing":{"type":"string"},"plan_area":{"type":"number"},"surface_area":{"type":"number"}}}},"obstacles":{"type":"array","items":{"type":"object"}}}},"Solar":{"type":"object","properties":{"module":{"type":"object"},"setback_m":{"type":"number"},"loss_percent":{"type":"number"},"weather_source":{"type":["string","null"]},"most_production":{"type":["string","null"]},"layouts":{"type":"object","additionalProperties":{"type":"object","properties":{"name":{"type":"string"},"panels":{"type":"integer"},"installed_kw_dc":{"type":"number"},"annual_kwh":{"type":["number","null"]},"specific_yield_kwh_per_kwp":{"type":["number","null"]},"shade_loss_percent":{"type":["number","null"]},"monthly_kwh":{"type":["array","null"],"items":{"type":"number"}}}}},"slopes":{"type":"array","items":{"type":"object"}}}},"Usage":{"type":"object","properties":{"key_name":{"type":"string"},"key_prefix":{"type":"string"},"date":{"type":"string"},"builds_today":{"type":"integer","description":"Successful new roofs today; only these count against the limit."},"builds_in_progress":{"type":"integer","description":"Builds still running; they hold their place until they end."},"failed_today":{"type":"integer","description":"Failed builds today; they do not count."},"daily_build_limit":{"type":"integer"},"remaining_today":{"type":"integer"},"roofs":{"type":"integer"}}}}}}