{"openapi":"3.1.0","info":{"title":"Solar Row Spacing API","version":"1.0.0","description":"Solar-array row-spacing and shading geometry as an API, computed locally and deterministically — the shadow-length, inter-row-spacing and ground-coverage numbers a PV designer or installer lays a ground-mount or flat-roof array out with. The shadow-length endpoint gives the shadow an object casts = its height ÷ tan(sun elevation), longer the lower the sun (which is why layouts are designed for the worst-case winter-solstice low sun), stretched by 1/cos(azimuth difference) when the sun is off-axis. The row-spacing endpoint gives the minimum row pitch (front edge to front edge) to stop a row shading the one behind = the module's horizontal base (length × cos tilt) + the shadow its back edge casts (module height ÷ tan of the minimum sun elevation) — a 1.7 m module at 30° tilt clearing a 20° winter sun needs about a 3.8 m pitch — and returns the resulting ground coverage ratio. The ground-coverage endpoint gives that GCR = module length ÷ row pitch, the packing density: fixed-tilt fields typically run 0.4–0.5, higher packs more kW per acre but loses winter yield to mutual shading, lower wastes land. Everything is computed locally and deterministically, so it is instant and private. Ideal for solar-design and layout tools, EPC and site-assessment apps, and renewable-energy calculators. Pure local computation — no key, no third-party service, instant. Geometric model — use the real worst-hour sun altitude. 3 compute endpoints. For solar position/altitude use a solar-position API; for irradiance a solar API; for off-grid sizing an off-grid API.","contact":{"name":"PremiumApi","url":"https://www.oanor.com/by/premiumapi"}},"servers":[{"url":"https://api.oanor.com/pvspacing-api","description":"oanor gateway"}],"tags":[{"name":"PV"},{"name":"Meta"}],"components":{"securitySchemes":{"oanorKey":{"type":"apiKey","in":"header","name":"x-oanor-key","description":"Get your key at https://www.oanor.com/developer/keys"}}},"security":[{"oanorKey":[]}],"paths":{"/v1/ground-coverage":{"get":{"operationId":"get_v1_ground_coverage","tags":["PV"],"summary":"Ground coverage ratio","description":"","parameters":[{"name":"module_length_m","in":"query","required":true,"description":"Module length (m)","schema":{"type":"string"},"example":"1.7"},{"name":"row_pitch_m","in":"query","required":true,"description":"Row pitch (m)","schema":{"type":"string"},"example":"3.807"}],"security":[{"oanorKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"data":{"note":"Ground coverage ratio = the module length ÷ the row pitch, the fraction of the ground the modules would cover if laid flat — a packing-density measure. Typical fixed-tilt fields run 0.4–0.5 GCR; higher packs more capacity into the land but raises mutual shading and the diffuse-light loss, lower wastes land. Trackers and high latitudes use lower GCR; flat, low-latitude sites can go higher.","inputs":{"row_pitch_m":3.807,"module_length_m":1.7},"ground_coverage_pct":44.65,"ground_coverage_ratio":0.4465},"meta":{"timestamp":"2026-06-07T08:17:56.583Z","request_id":"1d9eb204-1ec4-4261-8fde-949eea47e7db"},"status":"ok","message":"Ground coverage","success":true}}}},"401":{"description":"Missing or invalid x-oanor-key header"},"402":{"description":"Active subscription required"},"429":{"description":"Rate-limit or monthly quota reached"},"502":{"description":"Upstream did not respond"}}}},"/v1/row-spacing":{"get":{"operationId":"get_v1_row_spacing","tags":["PV"],"summary":"Minimum row pitch","description":"","parameters":[{"name":"module_length_m","in":"query","required":true,"description":"Module along-slope length (m)","schema":{"type":"string"},"example":"1.7"},{"name":"tilt_deg","in":"query","required":true,"description":"Module tilt (degrees)","schema":{"type":"string"},"example":"30"},{"name":"min_sun_elevation_deg","in":"query","required":true,"description":"Worst-case sun elevation (degrees)","schema":{"type":"string"},"example":"20"},{"name":"azimuth_difference_deg","in":"query","required":false,"description":"Azimuth difference (deg, default 0)","schema":{"type":"string"},"example":"0"}],"security":[{"oanorKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"data":{"note":"The minimum row pitch (front-edge to front-edge) = the module's horizontal base (length·cos tilt) + the shadow its back edge casts (height ÷ tan(min sun elevation)). Use the lowest sun you need clear — typically the winter-solstice altitude at solar noon — so the rows never shade each other in the worst hours. Tighter spacing packs more kW per acre but loses winter yield to mutual shading; the ground coverage ratio measures that trade.","inputs":{"tilt_deg":30,"module_length_m":1.7,"min_sun_elevation_deg":20,"azimuth_difference_deg":0},"module_base_m":1.472,"min_row_pitch_m":3.808,"module_height_m":0.85,"shadow_clearance_m":2.335,"ground_coverage_ratio":0.4465},"meta":{"timestamp":"2026-06-07T08:17:56.652Z","request_id":"149ea60d-ea62-4e56-937d-93a47ccb9b6f"},"status":"ok","message":"Row spacing","success":true}}}},"401":{"description":"Missing or invalid x-oanor-key header"},"402":{"description":"Active subscription required"},"429":{"description":"Rate-limit or monthly quota reached"},"502":{"description":"Upstream did not respond"}}}},"/v1/shadow-length":{"get":{"operationId":"get_v1_shadow_length","tags":["PV"],"summary":"Shadow length from height and sun","description":"","parameters":[{"name":"object_height_m","in":"query","required":true,"description":"Object height (m)","schema":{"type":"string"},"example":"0.85"},{"name":"sun_elevation_deg","in":"query","required":true,"description":"Sun elevation (degrees)","schema":{"type":"string"},"example":"20"},{"name":"azimuth_difference_deg","in":"query","required":false,"description":"Sun-to-array azimuth difference (deg, default 0)","schema":{"type":"string"},"example":"0"}],"security":[{"oanorKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"data":{"note":"Shadow length = object height ÷ tan(sun elevation). The lower the sun, the longer the shadow — which is why solar layouts are designed for the worst case, the winter-solstice low sun. When the sun is not square to the rows, the shadow cast across the row direction stretches by 1/cos(azimuth difference), so off-noon and off-south the shading reaches further.","inputs":{"object_height_m":0.85,"sun_elevation_deg":20,"azimuth_difference_deg":0},"shadow_length_m":2.335},"meta":{"timestamp":"2026-06-07T08:17:56.739Z","request_id":"47f8688d-e22c-430d-a2f5-82c3e711de7b"},"status":"ok","message":"Shadow length","success":true}}}},"401":{"description":"Missing or invalid x-oanor-key header"},"402":{"description":"Active subscription required"},"429":{"description":"Rate-limit or monthly quota reached"},"502":{"description":"Upstream did not respond"}}}},"/v1/meta":{"get":{"operationId":"get_v1_meta","tags":["Meta"],"summary":"Spec","description":"","parameters":[],"security":[{"oanorKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"data":{"notes":"Metres, degrees. shadow = height/tan(elev)/cos(Δazimuth); module height = length·sin(tilt); pitch = length·cos(tilt) + shadow; GCR = length/pitch. Design for the worst (winter) sun. For solar position/altitude use a solar-position API; for irradiance a solar API.","service":"pvspacing-api","endpoints":{"GET /v1/meta":"This document.","GET /v1/row-spacing":"Minimum row pitch to avoid self-shading.","GET /v1/shadow-length":"Shadow length from height and sun elevation.","GET /v1/ground-coverage":"Ground coverage ratio from module length and pitch."},"description":"Solar-array row-spacing and shading geometry: shadow length, minimum inter-row spacing, and ground coverage ratio."},"meta":{"timestamp":"2026-06-07T08:17:56.838Z","request_id":"01a66dff-09fd-43bf-9d69-3705588fe9e3"},"status":"ok","message":"Meta","success":true}}}},"401":{"description":"Missing or invalid x-oanor-key header"},"402":{"description":"Active subscription required"},"429":{"description":"Rate-limit or monthly quota reached"},"502":{"description":"Upstream did not respond"}}}}},"x-oanor-pricing":[{"slug":"free","name":"Free","price_cents_month":0,"monthly_call_quota":6700,"rps_limit":2,"hard_limit":true},{"slug":"starter","name":"Starter","price_cents_month":980,"monthly_call_quota":67500,"rps_limit":6,"hard_limit":true},{"slug":"pro","name":"Pro","price_cents_month":3120,"monthly_call_quota":278000,"rps_limit":15,"hard_limit":true},{"slug":"mega","name":"Mega","price_cents_month":9600,"monthly_call_quota":1365000,"rps_limit":40,"hard_limit":true}],"x-oanor-marketplace-url":"https://www.oanor.com/api/pvspacing-api"}