{"openapi":"3.0.0","info":{"title":"when.garden API","version":"1.0.0","description":"Location-specific frost dates, growing-season data and per-crop planting calendars. Per-location lookups only — no bulk export. Every response carries a confidence score and source (station vs modeled)."},"servers":[{"url":"/api"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key as `Authorization: Bearer wg_<id>_<secret>`."}},"schemas":{"Location":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"admin1":{"type":"string","nullable":true},"country":{"type":"string"},"lat":{"type":"number"},"lon":{"type":"number"},"koppen":{"type":"string"},"koppen_name":{"type":"string"},"regime":{"type":"string","enum":["frost","tropical"]},"confidence":{"type":"number","description":"0–100 confidence for this location's data.","example":88},"source":{"type":"string","enum":["station","modeled"],"description":"Nearby station vs modeled grid."}},"required":["slug","name","admin1","country","lat","lon","koppen","koppen_name","regime","confidence","source"]},"FrostDates":{"type":"object","properties":{"location":{"$ref":"#/components/schemas/Location"},"last_frost_50":{"type":"string","nullable":true,"description":"MM-DD, 50% probability.","example":"04-15"},"last_frost_10":{"type":"string","nullable":true},"first_frost_50":{"type":"string","nullable":true},"first_frost_10":{"type":"string","nullable":true},"frost_free_days":{"type":"number","nullable":true},"gdd10":{"type":"number","nullable":true},"gdd0":{"type":"number","nullable":true},"confidence":{"type":"number","description":"0–100 confidence for this location's data.","example":88},"source":{"type":"string","enum":["station","modeled"],"description":"Nearby station vs modeled grid."}},"required":["location","last_frost_50","last_frost_10","first_frost_50","first_frost_10","frost_free_days","gdd10","gdd0","confidence","source"]},"Error":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"]},"CalendarEntry":{"type":"object","properties":{"crop":{"type":"string"},"action":{"type":"string","enum":["start_indoor","transplant","direct_sow","harvest"]},"date_start":{"type":"string","example":"03-04"},"date_end":{"type":"string"},"confidence":{"type":"number"}},"required":["crop","action","date_start","date_end","confidence"]},"Calendar":{"type":"object","properties":{"location":{"$ref":"#/components/schemas/Location"},"calendar":{"type":"array","items":{"$ref":"#/components/schemas/CalendarEntry"}},"confidence":{"type":"number","description":"0–100 confidence for this location's data.","example":88},"source":{"type":"string","enum":["station","modeled"],"description":"Nearby station vs modeled grid."}},"required":["location","calendar","confidence","source"]},"Crop":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"category":{"type":"string"},"frost_tolerance":{"type":"string"},"min_soil_temp_c":{"type":"number","nullable":true},"dtm_min":{"type":"number","nullable":true},"dtm_max":{"type":"number","nullable":true},"photoperiod_note":{"type":"string","nullable":true}},"required":["slug","name","category","frost_tolerance","min_soil_temp_c","dtm_min","dtm_max","photoperiod_note"]},"ClimateZone":{"type":"object","properties":{"koppen":{"type":"string"},"koppen_name":{"type":"string"},"regime":{"type":"string","enum":["frost","tropical"]},"nearest_location":{"allOf":[{"$ref":"#/components/schemas/Location"},{"nullable":true}]},"distance_km":{"type":"number","nullable":true}},"required":["koppen","koppen_name","regime","nearest_location","distance_km"]}},"parameters":{}},"paths":{"/v1/frost-dates":{"get":{"tags":["Frost"],"security":[{"bearerAuth":[]}],"summary":"Frost dates for a location (by slug or lat/lon)","parameters":[{"schema":{"type":"string","example":"au/melbourne"},"required":false,"name":"location","in":"query"},{"schema":{"type":"number","nullable":true},"required":false,"name":"lat","in":"query"},{"schema":{"type":"number","nullable":true},"required":false,"name":"lon","in":"query"}],"responses":{"200":{"description":"Frost statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FrostDates"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/locations/{slug}/calendar":{"get":{"tags":["Calendar"],"security":[{"bearerAuth":[]}],"summary":"Full planting calendar for a location","parameters":[{"schema":{"type":"string","example":"melbourne"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Calendar","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Calendar"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/locations/{slug}/crops/{crop}":{"get":{"tags":["Calendar"],"security":[{"bearerAuth":[]}],"summary":"Calendar for one crop at one location","parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"crop","in":"path"}],"responses":{"200":{"description":"Calendar","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Calendar"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/crops":{"get":{"tags":["Crops"],"security":[{"bearerAuth":[]}],"summary":"Crop dictionary (reference data; not the location dataset)","responses":{"200":{"description":"Crops","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Crop"}}}}}}}},"/v1/crops/{slug}":{"get":{"tags":["Crops"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Crop","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Crop"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/climate-zone":{"get":{"tags":["Climate"],"security":[{"bearerAuth":[]}],"summary":"Köppen climate zone for a coordinate (via nearest location)","parameters":[{"schema":{"type":"number","nullable":true},"required":false,"name":"lat","in":"query"},{"schema":{"type":"number","nullable":true},"required":false,"name":"lon","in":"query"}],"responses":{"200":{"description":"Zone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClimateZone"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}