{"openapi":"3.1.0","info":{"title":"Wildlife photo hides and lodges API","version":"v1","description":"JSON API behind the website, apps and MCP server: species, places, shooting windows and listings (hides, lodges, tours), all read only, plus one write: POST /api/v1/feedback for the contact, feedback and correction forms. No authentication in phase 1. Field names are camelCase; query parameters are snake_case. Lists in query strings are comma separated."},"servers":[{"url":"/"}],"tags":[{"name":"search"},{"name":"species"},{"name":"places"},{"name":"windows"},{"name":"listings"},{"name":"rates"},{"name":"feedback"}],"paths":{"/api/v1/search":{"get":{"operationId":"search","tags":["search"],"summary":"Search species, places and listings","parameters":[{"in":"query","name":"q","schema":{"description":"Free text.","example":"lynx","type":"string","maxLength":200},"description":"Free text."},{"in":"query","name":"limit","schema":{"default":8,"description":"Maximum hits per group (default 8, max 25).","type":"integer","minimum":1,"maximum":25},"description":"Maximum hits per group (default 8, max 25)."}],"responses":{"200":{"description":"Grouped hits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/species":{"get":{"operationId":"listSpecies","tags":["species"],"summary":"List or search species","parameters":[{"in":"query","name":"q","schema":{"description":"Free text.","example":"lynx","type":"string","maxLength":200},"description":"Free text."},{"in":"query","name":"slugs","schema":{"type":"string","description":"Only these species (slugs or public ids, comma separated, at most 20), in that order; q is ignored. Unknown ones are left out.","example":"eurasian-lynx,brown-bear"}},{"in":"query","name":"limit","schema":{"default":50,"description":"Maximum results (default 50, max 200).","type":"integer","minimum":1,"maximum":200},"description":"Maximum results (default 50, max 200)."}],"responses":{"200":{"description":"Species","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeciesListResponse"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/species/{slug}":{"get":{"operationId":"getSpecies","tags":["species"],"summary":"A species with its window grid and listings","parameters":[{"in":"path","name":"slug","schema":{"type":"string","description":"Species slug or public id.","example":"eurasian-lynx"},"required":true,"description":"Species slug or public id."}],"responses":{"200":{"description":"Species","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeciesDetail"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/species/{slug}/range":{"get":{"operationId":"getSpeciesRange","tags":["species"],"summary":"Where a species lives: range sources and the bbox to fit the camera","parameters":[{"in":"path","name":"slug","schema":{"type":"string","description":"Species slug or public id.","example":"eurasian-lynx"},"required":true,"description":"Species slug or public id."}],"responses":{"200":{"description":"Range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeciesRangeResponse"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/places/{path}":{"get":{"operationId":"getPlace","tags":["places"],"summary":"A continent, country or park with windows, species and listings","parameters":[{"in":"path","name":"path","schema":{"type":"string","description":"Slug path such as \"europe/finland/oulanka\" (slashes may be URL encoded), or a place public id.","example":"europe/finland"},"required":true,"description":"Slug path such as \"europe/finland/oulanka\" (slashes may be URL encoded), or a place public id."},{"in":"query","name":"species","schema":{"type":"string","description":"Species slugs (or public ids), comma separated.","example":"eurasian-lynx,brown-bear"}},{"in":"query","name":"months","schema":{"type":"string","description":"Months, 1 to 12 or English names, comma separated.","example":"6,7"}},{"in":"query","name":"types","schema":{"type":"string","description":"Listing types, comma separated: hide, lodge, tour, workshop, guide.","example":"hide,lodge"}},{"in":"query","name":"price_min","schema":{"description":"Minimum price_from, in the listing currency.","type":"number","minimum":0},"description":"Minimum price_from, in the listing currency."},{"in":"query","name":"price_max","schema":{"description":"Maximum price_from, in the listing currency.","type":"number","minimum":0},"description":"Maximum price_from, in the listing currency."},{"in":"query","name":"sort","schema":{"default":"rank","type":"string","enum":["rank","price_asc","price_desc","distance","odds"]}},{"in":"query","name":"limit","schema":{"default":100,"description":"Maximum results (default 100, max 500).","type":"integer","minimum":1,"maximum":500},"description":"Maximum results (default 100, max 500)."}],"responses":{"200":{"description":"Place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceDetail"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/places/{path}/conditions":{"get":{"operationId":"getPlaceConditions","tags":["places"],"summary":"Light and weather at a park's centroid: today's sun times, golden and blue hour in its time zone, the month light table and the current weather (MET Norway). Not for continents or countries (404)","parameters":[{"in":"path","name":"path","schema":{"type":"string","description":"Slug path such as \"europe/finland/oulanka\" (slashes may be URL encoded), or a place public id.","example":"europe/finland"},"required":true,"description":"Slug path such as \"europe/finland/oulanka\" (slashes may be URL encoded), or a place public id."}],"responses":{"200":{"description":"Light and conditions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceConditions"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/national-parks":{"get":{"operationId":"listNationalParks","tags":["places"],"summary":"National parks of a country (or everywhere) with listing counts","parameters":[{"in":"query","name":"country","schema":{"description":"A country by slug path (\"europe/finland\") or ISO 3166-1 alpha-2 code (\"FI\"). Omitted: national parks everywhere, plus the countries that have them.","example":"europe/finland","type":"string","maxLength":200},"description":"A country by slug path (\"europe/finland\") or ISO 3166-1 alpha-2 code (\"FI\"). Omitted: national parks everywhere, plus the countries that have them."},{"in":"query","name":"limit","schema":{"default":200,"description":"Maximum results (default 200, max 1000).","type":"integer","minimum":1,"maximum":1000},"description":"Maximum results (default 200, max 1000)."}],"responses":{"200":{"description":"National parks, most listings first","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NationalParksResponse"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/windows":{"get":{"operationId":"listWindows","tags":["windows"],"summary":"Shooting windows for the globe filter","parameters":[{"in":"query","name":"species","schema":{"type":"string","description":"Species slugs (or public ids), comma separated.","example":"eurasian-lynx,brown-bear"}},{"in":"query","name":"months","schema":{"type":"string","description":"Months, 1 to 12 or English names, comma separated.","example":"6,7"}},{"in":"query","name":"bbox","schema":{"type":"string","description":"Bounding box \"west,south,east,north\" in degrees. west > east crosses the antimeridian.","example":"20,59,32,70"}},{"in":"query","name":"verdict","schema":{"type":"string","description":"Only windows with these verdicts. Needs WINDOW_PUBLIC_VERDICT (the default). Comma separated: prime, good, acceptable, avoid."}},{"in":"query","name":"odds","schema":{"type":"string","description":"Only windows with these odds. Comma separated: near_certain, likely, coin_flip, long_shot, lottery."}},{"in":"query","name":"limit","schema":{"default":500,"description":"Maximum results (default 500, max 5000).","type":"integer","minimum":1,"maximum":5000},"description":"Maximum results (default 500, max 5000)."}],"responses":{"200":{"description":"Windows","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WindowsResponse"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/listings":{"get":{"operationId":"listListings","tags":["listings"],"summary":"Listings as globe markers with card fields","parameters":[{"in":"query","name":"bbox","schema":{"type":"string","description":"Bounding box \"west,south,east,north\" in degrees. west > east crosses the antimeridian.","example":"20,59,32,70"}},{"in":"query","name":"ids","schema":{"type":"string","description":"Only these listings: uuids or public ids, comma separated (at most 100). The other filters still apply. Used by the globe to load card fields for the rows its list shows.","example":"7k2m9q4xzt,3h8w2p6rnc"}},{"in":"query","name":"species","schema":{"type":"string","description":"Species slugs (or public ids), comma separated.","example":"eurasian-lynx,brown-bear"}},{"in":"query","name":"months","schema":{"type":"string","description":"Months, 1 to 12 or English names, comma separated.","example":"6,7"}},{"in":"query","name":"types","schema":{"type":"string","description":"Listing types, comma separated: hide, lodge, tour, workshop, guide.","example":"hide,lodge"}},{"in":"query","name":"verdict","schema":{"type":"string","description":"Only listings whose best open verdict (the item's `verdict`) is one of these. Needs WINDOW_PUBLIC_VERDICT (the default). Comma separated: prime, good, acceptable."}},{"in":"query","name":"price_min","schema":{"description":"Minimum price_from, in the listing currency.","type":"number","minimum":0},"description":"Minimum price_from, in the listing currency."},{"in":"query","name":"price_max","schema":{"description":"Maximum price_from, in the listing currency.","type":"number","minimum":0},"description":"Maximum price_from, in the listing currency."},{"in":"query","name":"currency","schema":{"description":"Only listings priced in this ISO 4217 currency.","type":"string","pattern":"^[A-Za-z]{3}$"},"description":"Only listings priced in this ISO 4217 currency."},{"in":"query","name":"price_currency","schema":{"description":"price_min and price_max are in this ISO 4217 currency: every listing's price_from is converted with the day's ECB reference rates before comparing (approximate). A listing in a currency without a rate never matches a price bound. Also sorts price_asc and price_desc across currencies.","example":"GBP","type":"string","pattern":"^[A-Za-z]{3}$"},"description":"price_min and price_max are in this ISO 4217 currency: every listing's price_from is converted with the day's ECB reference rates before comparing (approximate). A listing in a currency without a rate never matches a price bound. Also sorts price_asc and price_desc across currencies."},{"in":"query","name":"unpriced","schema":{"default":"exclude","description":"With price_min or price_max: include keeps listings without a price (price on request).","type":"string","enum":["include","exclude"]},"description":"With price_min or price_max: include keeps listings without a price (price on request)."},{"in":"query","name":"lens_mm","schema":{"description":"The longest focal length the visitor has, in mm full-frame equivalent: only listings whose needed focal length is within reach. A listing needs its own details.focalLengthMm.min, else the shortest focal length its species' lens advice gives (only the species in `species`, when set).","example":400,"type":"integer","minimum":1,"maximum":2000},"description":"The longest focal length the visitor has, in mm full-frame equivalent: only listings whose needed focal length is within reach. A listing needs its own details.focalLengthMm.min, else the shortest focal length its species' lens advice gives (only the species in `species`, when set)."},{"in":"query","name":"lens_unknown","schema":{"default":"exclude","description":"With lens_mm: include keeps listings with no lens advice at all.","type":"string","enum":["include","exclude"]},"description":"With lens_mm: include keeps listings with no lens advice at all."},{"in":"query","name":"park","schema":{"description":"national: only listings inside a national park (the protected area around the point, or one it overlaps there, has designation class national_park).","type":"string","enum":["national"]},"description":"national: only listings inside a national park (the protected area around the point, or one it overlaps there, has designation class national_park)."},{"in":"query","name":"place","schema":{"description":"Only listings in this place (slug path), as its list page counts them: inside it, in one of its parks, or attached to it.","example":"europe/finland","type":"string","maxLength":200,"pattern":"^[a-z0-9-]+(?:\\/[a-z0-9-]+){0,4}$"},"description":"Only listings in this place (slug path), as its list page counts them: inside it, in one of its parks, or attached to it."},{"in":"query","name":"sort","schema":{"default":"rank","description":"rank (date proximity, then claimed and verified, then completeness), price_asc, price_desc, distance (to the park boundary), odds.","type":"string","enum":["rank","price_asc","price_desc","distance","odds"]},"description":"rank (date proximity, then claimed and verified, then completeness), price_asc, price_desc, distance (to the park boundary), odds."},{"in":"query","name":"match","schema":{"default":"filter","description":"filter drops listings that do not match species/months/types/verdict; fade (for the globe) still drops species and type mismatches but keeps month and verdict mismatches with faded=true.","type":"string","enum":["filter","fade"]},"description":"filter drops listings that do not match species/months/types/verdict; fade (for the globe) still drops species and type mismatches but keeps month and verdict mismatches with faded=true."},{"in":"query","name":"dev","schema":{"description":"Developer mode: 1 adds fadeReasons and debug.hidden. Ignored unless the server sets PBS_DEV_TOOLS.","type":"string","enum":["0","1"]},"description":"Developer mode: 1 adds fadeReasons and debug.hidden. Ignored unless the server sets PBS_DEV_TOOLS."},{"in":"query","name":"limit","schema":{"default":200,"description":"Maximum results (default 200, max 2000).","type":"integer","minimum":1,"maximum":2000},"description":"Maximum results (default 200, max 2000)."}],"responses":{"200":{"description":"Listings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingsResponse"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/markers":{"get":{"operationId":"listMarkers","tags":["listings"],"summary":"Every globe marker for the filters, without card fields","parameters":[{"in":"query","name":"bbox","schema":{"type":"string","description":"Bounding box \"west,south,east,north\" in degrees. west > east crosses the antimeridian.","example":"20,59,32,70"}},{"in":"query","name":"species","schema":{"type":"string","description":"Species slugs (or public ids), comma separated.","example":"eurasian-lynx,brown-bear"}},{"in":"query","name":"months","schema":{"type":"string","description":"Months, 1 to 12 or English names, comma separated.","example":"6,7"}},{"in":"query","name":"types","schema":{"type":"string","description":"Listing types, comma separated: hide, lodge, tour, workshop, guide.","example":"hide,lodge"}},{"in":"query","name":"verdict","schema":{"type":"string","description":"Only listings whose best open verdict (the item's `verdict`) is one of these. Needs WINDOW_PUBLIC_VERDICT (the default). Comma separated: prime, good, acceptable."}},{"in":"query","name":"price_min","schema":{"description":"Minimum price_from, in the listing currency.","type":"number","minimum":0},"description":"Minimum price_from, in the listing currency."},{"in":"query","name":"price_max","schema":{"description":"Maximum price_from, in the listing currency.","type":"number","minimum":0},"description":"Maximum price_from, in the listing currency."},{"in":"query","name":"currency","schema":{"description":"Only listings priced in this ISO 4217 currency.","type":"string","pattern":"^[A-Za-z]{3}$"},"description":"Only listings priced in this ISO 4217 currency."},{"in":"query","name":"price_currency","schema":{"description":"price_min and price_max are in this ISO 4217 currency: every listing's price_from is converted with the day's ECB reference rates before comparing (approximate). A listing in a currency without a rate never matches a price bound. Also sorts price_asc and price_desc across currencies.","example":"GBP","type":"string","pattern":"^[A-Za-z]{3}$"},"description":"price_min and price_max are in this ISO 4217 currency: every listing's price_from is converted with the day's ECB reference rates before comparing (approximate). A listing in a currency without a rate never matches a price bound. Also sorts price_asc and price_desc across currencies."},{"in":"query","name":"unpriced","schema":{"default":"exclude","description":"With price_min or price_max: include keeps listings without a price (price on request).","type":"string","enum":["include","exclude"]},"description":"With price_min or price_max: include keeps listings without a price (price on request)."},{"in":"query","name":"lens_mm","schema":{"description":"The longest focal length the visitor has, in mm full-frame equivalent: only listings whose needed focal length is within reach. A listing needs its own details.focalLengthMm.min, else the shortest focal length its species' lens advice gives (only the species in `species`, when set).","example":400,"type":"integer","minimum":1,"maximum":2000},"description":"The longest focal length the visitor has, in mm full-frame equivalent: only listings whose needed focal length is within reach. A listing needs its own details.focalLengthMm.min, else the shortest focal length its species' lens advice gives (only the species in `species`, when set)."},{"in":"query","name":"lens_unknown","schema":{"default":"exclude","description":"With lens_mm: include keeps listings with no lens advice at all.","type":"string","enum":["include","exclude"]},"description":"With lens_mm: include keeps listings with no lens advice at all."},{"in":"query","name":"park","schema":{"description":"national: only listings inside a national park (the protected area around the point, or one it overlaps there, has designation class national_park).","type":"string","enum":["national"]},"description":"national: only listings inside a national park (the protected area around the point, or one it overlaps there, has designation class national_park)."},{"in":"query","name":"place","schema":{"description":"Only listings in this place (slug path), as its list page counts them: inside it, in one of its parks, or attached to it.","example":"europe/finland","type":"string","maxLength":200,"pattern":"^[a-z0-9-]+(?:\\/[a-z0-9-]+){0,4}$"},"description":"Only listings in this place (slug path), as its list page counts them: inside it, in one of its parks, or attached to it."},{"in":"query","name":"sort","schema":{"default":"rank","description":"rank (date proximity, then claimed and verified, then completeness), price_asc, price_desc, distance (to the park boundary), odds.","type":"string","enum":["rank","price_asc","price_desc","distance","odds"]},"description":"rank (date proximity, then claimed and verified, then completeness), price_asc, price_desc, distance (to the park boundary), odds."},{"in":"query","name":"match","schema":{"default":"fade","description":"As for /api/v1/listings, but fade (the globe) is the default.","type":"string","enum":["filter","fade"]},"description":"As for /api/v1/listings, but fade (the globe) is the default."},{"in":"query","name":"dev","schema":{"description":"Developer mode: 1 adds fadeReasons and debug.hidden. Ignored unless the server sets PBS_DEV_TOOLS.","type":"string","enum":["0","1"]},"description":"Developer mode: 1 adds fadeReasons and debug.hidden. Ignored unless the server sets PBS_DEV_TOOLS."},{"in":"query","name":"limit","schema":{"default":5000,"description":"Maximum results (default 5000, max 5000).","type":"integer","minimum":1,"maximum":5000},"description":"Maximum results (default 5000, max 5000)."}],"responses":{"200":{"description":"Markers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkersResponse"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/listings/along":{"get":{"operationId":"listAlong","tags":["listings"],"summary":"Listings along a trip route (the trip planner's \"Along the way\")","parameters":[{"in":"query","name":"route","schema":{"type":"string","maxLength":1000,"description":"The trip's stops in order, \"lng,lat\" separated by \";\" (at most 20). Stops are joined by great-circle legs; \"|\" starts a new part, so a leg can be left out (the trip page leaves out flights). A part of one stop means around that stop.","example":"24.94,60.17;25.47,65.01|29.18,65.97"},"required":true},{"in":"query","name":"km","schema":{"default":50,"description":"Corridor width in kilometres either side of the route (10 to 200, default 50).","type":"integer","minimum":10,"maximum":200},"description":"Corridor width in kilometres either side of the route (10 to 200, default 50)."},{"in":"query","name":"from","schema":{"description":"First day of the trip. With it, only listings open in the trip's months (or all year) are returned.","example":"2027-06-10","type":"string"},"description":"First day of the trip. With it, only listings open in the trip's months (or all year) are returned."},{"in":"query","name":"to","schema":{"description":"Last day of the trip (default: the first day). Needs from.","example":"2027-06-10","type":"string"},"description":"Last day of the trip (default: the first day). Needs from."},{"in":"query","name":"limit","schema":{"default":24,"description":"Maximum results (default 24, max 50).","type":"integer","minimum":1,"maximum":50},"description":"Maximum results (default 24, max 50)."}],"responses":{"200":{"description":"Listings along the route","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlongResponse"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/listings/{id}":{"get":{"operationId":"getListing","tags":["listings"],"summary":"One listing: photos, species, months, badge, booking link","parameters":[{"in":"path","name":"id","schema":{"type":"string","description":"Listing uuid or public id; \"publicid-slug\" is accepted too.","example":"7k2m9q4xzt"},"required":true,"description":"Listing uuid or public id; \"publicid-slug\" is accepted too."}],"responses":{"200":{"description":"Listing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingDetail"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/listings/{id}/conditions":{"get":{"operationId":"getListingConditions","tags":["listings"],"summary":"Light and weather at a listing: today's sun times, golden and blue hour in its time zone, the month light table and the current weather (MET Norway)","parameters":[{"in":"path","name":"id","schema":{"type":"string","description":"Listing uuid or public id; \"publicid-slug\" is accepted too.","example":"7k2m9q4xzt"},"required":true,"description":"Listing uuid or public id; \"publicid-slug\" is accepted too."}],"responses":{"200":{"description":"Light and conditions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingConditions"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/in-season":{"get":{"operationId":"getInSeason","tags":["windows"],"summary":"What is in season in a country this month (opening sequence)","parameters":[{"in":"query","name":"country","schema":{"description":"ISO 3166-1 alpha-2 country code. Unknown or missing opens on Europe.","type":"string","pattern":"^[A-Za-z]{2}$"},"description":"ISO 3166-1 alpha-2 country code. Unknown or missing opens on Europe."},{"in":"query","name":"month","schema":{"description":"Month 1..12; defaults to the current month (UTC).","type":"integer","minimum":1,"maximum":12},"description":"Month 1..12; defaults to the current month (UTC)."},{"in":"query","name":"markers","schema":{"default":"1","description":"Include listing markers inside the area (1, default) or not (0).","type":"string","enum":["0","1"]},"description":"Include listing markers inside the area (1, default) or not (0)."}],"responses":{"200":{"description":"In season","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InSeason"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/rates":{"get":{"operationId":"getRates","tags":["rates"],"summary":"EUR based reference rates for approximate price conversion","responses":{"200":{"description":"Rates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RatesResponse"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The rates source is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/feedback":{"post":{"operationId":"submitFeedback","tags":["feedback"],"summary":"Send a contact message, site feedback or a listing correction","description":"Stored first, then the owner is notified when email is configured. Never cached. Spam protection: a honeypot field (`website`), a minimum fill time (`elapsedMs` of at least 3000; forms that fail either get 200 and are dropped), Cloudflare Turnstile when the server has it on, and at most 5 messages per hour per visitor (429, checked again atomically when storing). The hourly limit and the listing lookup run before Turnstile, so a 429 or 404 does not use up a token. The raw IP address is never stored.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackRequest"}}}},"responses":{"200":{"description":"Received","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackResponse"}}}},"400":{"description":"Invalid message, or the Turnstile check failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The listing a correction names does not exist or is not published","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many messages from this visitor in the last hour","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/openapi.json":{"get":{"operationId":"getOpenApi","summary":"This document","responses":{"200":{"description":"OpenAPI 3.1 document"}}}}},"components":{"schemas":{"FeedbackRequest":{"type":"object","properties":{"kind":{"type":"string","enum":["contact","feedback","correction"],"description":"contact (the contact page), feedback (about the site) or correction (about one listing)."},"message":{"type":"string","minLength":1,"maxLength":5000},"replyEmail":{"description":"Only if the visitor wants a reply. Stored with the message, never shown.","type":"string","maxLength":254,"format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"listingId":{"description":"Public id of the listing a correction is about.","type":"string","pattern":"^[0-9a-hjkmnp-tv-z]{10}$"},"category":{"description":"What a correction is about: location, park (inside or outside), species, price, closed (closed or moved) or other. Corrections without one are stored as other.","type":"string","enum":["location","park","species","price","closed","other"]},"pageUrl":{"description":"The page the form was sent from.","type":"string","maxLength":2000},"elapsedMs":{"description":"Milliseconds between the form appearing and being sent. Forms sent faster than a person can type are dropped as spam.","type":"integer","minimum":0,"maximum":9007199254740991},"website":{"description":"Honeypot: a hidden field people never fill in. Leave it out or empty.","type":"string"},"turnstileToken":{"description":"Cloudflare Turnstile token, required only when the server has Turnstile on.","type":"string","maxLength":2048}},"required":["kind","message"]},"SearchResponse":{"type":"object","properties":{"q":{"type":"string"},"intent":{"$ref":"#/components/schemas/SearchIntent"},"species":{"type":"array","items":{"$ref":"#/components/schemas/SpeciesHit"}},"places":{"type":"array","items":{"$ref":"#/components/schemas/PlaceHit"}},"listings":{"type":"array","items":{"$ref":"#/components/schemas/ListingHit"}},"organisations":{"type":"array","items":{"$ref":"#/components/schemas/PartyHit"}},"people":{"type":"array","items":{"$ref":"#/components/schemas/PartyHit"}}},"required":["q","species","places","listings","organisations","people"],"additionalProperties":false},"SearchIntent":{"type":"object","properties":{"kind":{"type":"string","const":"national_parks"},"country":{"anyOf":[{"type":"object","properties":{"name":{"type":"string"},"placePath":{"type":"string"},"path":{"type":"string","description":"Site URL path of the country's list page."},"bbox":{"anyOf":[{"$ref":"#/components/schemas/BBox"},{"type":"null"}]}},"required":["name","placePath","path","bbox"],"additionalProperties":false},{"type":"null"}],"description":"The country the query named; null for national parks anywhere."},"indexPath":{"type":"string","description":"Site URL path of the national parks page, e.g. \"/national-parks/europe/finland\"."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"National parks there (places lists the first)."}},"required":["kind","country","indexPath","total"],"additionalProperties":false,"description":"The query asked for a kind of place (\"national parks in Finland\"): `places` lists those places, most listings first, and species and listings are empty."},"BBox":{"type":"object","properties":{"west":{"type":"number"},"south":{"type":"number"},"east":{"type":"number"},"north":{"type":"number"}},"required":["west","south","east","north"],"additionalProperties":false,"description":"Bounding box in degrees; west > east crosses the antimeridian."},"SpeciesHit":{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"path":{"type":"string","description":"Site URL path."},"score":{"type":"number"},"kind":{"type":"string","const":"species"},"scientificName":{"type":"string"},"matchedName":{"type":"string"},"stripeColour":{"type":["string","null"]}},"required":["id","publicId","name","slug","path","score","kind","scientificName","matchedName","stripeColour"],"additionalProperties":false},"PlaceHit":{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"path":{"type":"string","description":"Site URL path."},"score":{"type":"number"},"kind":{"type":"string","const":"place"},"placeKind":{"$ref":"#/components/schemas/PlaceKind"},"placePath":{"type":"string"},"bbox":{"anyOf":[{"$ref":"#/components/schemas/BBox"},{"type":"null"}],"description":"Fly the globe here."},"centroid":{"anyOf":[{"$ref":"#/components/schemas/LngLat"},{"type":"null"}]},"context":{"description":"Parent place names, e.g. \"Finland\".","type":["string","null"]}},"required":["id","publicId","name","slug","path","score","kind","placeKind","placePath","bbox","centroid","context"],"additionalProperties":false},"PlaceKind":{"type":"string","enum":["continent","country","region","protected_area","site","city"]},"LngLat":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"}],"items":false,"minItems":2,"maxItems":2,"description":"[longitude, latitude] in degrees (WGS84)."},"ListingHit":{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"path":{"type":"string","description":"Site URL path."},"score":{"type":"number"},"kind":{"type":"string","const":"listing"},"type":{"$ref":"#/components/schemas/ListingType"},"position":{"anyOf":[{"$ref":"#/components/schemas/LngLat"},{"type":"null"}]},"organisationName":{"type":["string","null"]}},"required":["id","publicId","name","slug","path","score","kind","type","position","organisationName"],"additionalProperties":false},"ListingType":{"type":"string","enum":["hide","lodge","tour","workshop","guide"]},"PartyHit":{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"path":{"type":"string","description":"Site URL path."},"score":{"type":"number"},"kind":{"type":"string","enum":["organisation","person"]}},"required":["id","publicId","name","slug","path","score","kind"],"additionalProperties":false,"description":"Operators and photographers; empty until phase 2."},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","not_found","unsupported_filter","unavailable","rate_limited","verification_failed","internal_error"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false},"SpeciesListResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SpeciesListItem"}}},"required":["items"],"additionalProperties":false},"SpeciesListItem":{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"scientificName":{"type":"string"},"group":{"type":"string","enum":["mammal_terrestrial","mammal_marine","bird_raptor","bird_seabird","bird_other","reptile_amphibian","fish","invertebrate"]},"stripeColour":{"type":["string","null"]},"iucnStatus":{"type":["string","null"]},"path":{"type":"string"},"matchedName":{"description":"The name that matched q, if any.","type":["string","null"]}},"required":["id","publicId","slug","name","scientificName","group","stripeColour","iucnStatus","path","matchedName"],"additionalProperties":false},"SpeciesDetail":{"type":"object","properties":{"species":{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"scientificName":{"type":"string"},"group":{"type":"string","enum":["mammal_terrestrial","mammal_marine","bird_raptor","bird_seabird","bird_other","reptile_amphibian","fish","invertebrate"]},"stripeColour":{"type":["string","null"]},"iucnStatus":{"type":["string","null"]},"path":{"type":"string"},"lens":{"anyOf":[{"$ref":"#/components/schemas/SpeciesLens"},{"type":"null"}],"description":"Null when there is no lens advice."},"gbifTaxonKey":{"type":["number","null"]},"regions":{"type":"array","items":{"type":"string"}},"names":{"type":"array","items":{"type":"object","properties":{"lang":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["common","synonym","scientific"]},"isPrimary":{"type":"boolean"}},"required":["lang","name","kind","isPrimary"],"additionalProperties":false}}},"required":["id","publicId","slug","name","scientificName","group","stripeColour","iucnStatus","path","lens","gbifTaxonKey","regions","names"],"additionalProperties":false},"range":{"$ref":"#/components/schemas/RangeAvailability"},"grid":{"type":"array","items":{"$ref":"#/components/schemas/WindowGridRow"},"description":"Places down, months across."},"windows":{"type":"array","items":{"$ref":"#/components/schemas/Window"}},"listings":{"type":"array","items":{"$ref":"#/components/schemas/ListingItem"}},"creativeFields":{"type":"boolean"},"famousIndividuals":{"type":"array","items":{"$ref":"#/components/schemas/FamousResident"},"description":"Reviewed famous animals of this species, with their places."}},"required":["species","range","grid","windows","listings","creativeFields","famousIndividuals"],"additionalProperties":false},"SpeciesLens":{"type":"object","properties":{"focalLengths":{"type":"array","items":{"type":"string"},"description":"The lens options as researched, e.g. \"70-200\", \"300 + 1.4x TC\", \"Underwater wide\".","example":["70-200","300 f/2.8","600 f/4"]},"minMm":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Shortest focal length the options cover, full-frame equivalent."},"maxMm":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Longest focal length the options cover, full-frame equivalent (300 mm with a 2x teleconverter is 600)."},"underwater":{"type":"boolean","description":"A wide angle lens underwater is suggested."}},"required":["focalLengths","minMm","maxMm","underwater"],"additionalProperties":false,"description":"Focal lengths usually needed to photograph the species."},"RangeAvailability":{"type":"object","properties":{"sources":{"type":"array","items":{"type":"string","enum":["iucn","birdlife","ebird","gbif","other"]}},"hasPolygons":{"type":"boolean"},"hasOccurrenceCells":{"type":"boolean"},"occurrenceMonths":{"type":"array","items":{"type":"integer","minimum":1,"maximum":12}},"bbox":{"anyOf":[{"$ref":"#/components/schemas/BBox"},{"type":"null"}],"description":"Fit the camera to the whole range."}},"required":["sources","hasPolygons","hasOccurrenceCells","occurrenceMonths","bbox"],"additionalProperties":false},"WindowGridRow":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"place":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"name":{"type":"string"},"kind":{"$ref":"#/components/schemas/PlaceKind"},"placePath":{"type":"string"},"path":{"type":"string"}},"required":["id","publicId","name","kind","placePath","path"],"additionalProperties":false},{"type":"null"}]},"position":{"anyOf":[{"$ref":"#/components/schemas/LngLat"},{"type":"null"}]},"windowIds":{"type":"array","items":{"type":"string"}},"cells":{"minItems":12,"maxItems":12,"type":"array","items":{"$ref":"#/components/schemas/MonthCell"}}},"required":["key","label","place","position","windowIds","cells"],"additionalProperties":false,"description":"One place in a window grid; cells run January to December."},"MonthCell":{"type":"object","properties":{"month":{"type":"integer","minimum":1,"maximum":12},"open":{"type":"boolean"},"peak":{"type":"boolean"},"odds":{"anyOf":[{"$ref":"#/components/schemas/Odds"},{"type":"null"}]},"verdict":{"anyOf":[{"$ref":"#/components/schemas/Verdict"},{"type":"null"}],"description":"Null when the server hides verdicts (WINDOW_PUBLIC_VERDICT=false)."}},"required":["month","open","peak","odds","verdict"],"additionalProperties":false},"Odds":{"type":"string","enum":["near_certain","likely","coin_flip","long_shot","lottery"]},"Verdict":{"type":"string","enum":["prime","good","acceptable","avoid"]},"Window":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"species":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"scientificName":{"type":"string"},"stripeColour":{"type":["string","null"]},"path":{"type":"string"}},"required":["id","slug","name","scientificName","stripeColour","path"],"additionalProperties":false},{"type":"null"}]},"place":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"name":{"type":"string"},"kind":{"$ref":"#/components/schemas/PlaceKind"},"placePath":{"type":"string"},"path":{"type":"string"}},"required":["id","publicId","name","kind","placePath","path"],"additionalProperties":false},{"type":"null"}]},"locationText":{"type":["string","null"]},"countryText":{"type":["string","null"]},"position":{"anyOf":[{"$ref":"#/components/schemas/LngLat"},{"type":"null"}]},"bbox":{"anyOf":[{"$ref":"#/components/schemas/BBox"},{"type":"null"}]},"months":{"type":"array","items":{"type":"integer","minimum":1,"maximum":12}},"peakWeeksText":{"type":["string","null"]},"peakMonths":{"type":"array","items":{"type":"integer","minimum":1,"maximum":12},"description":"Months named in peakWeeksText."},"behaviour":{"type":"array","items":{"type":"string"}},"coatState":{"type":["string","null"]},"habitat":{"type":"array","items":{"type":"string"}},"odds":{"anyOf":[{"$ref":"#/components/schemas/Odds"},{"type":"null"}]},"crowds":{"type":["string","null"]},"daysNeeded":{"type":["number","null"]},"notes":{"type":"object","properties":{"light":{"type":["string","null"]},"weatherRisk":{"type":"array","items":{"type":"string"}},"tidesMoon":{"type":["string","null"]},"atmosphere":{"type":["string","null"]},"permits":{"type":["string","null"]},"logistics":{"type":["string","null"]}},"required":["light","weatherRisk","tidesMoon","atmosphere","permits","logistics"],"additionalProperties":false},"operatorsText":{"type":["string","null"]},"backupSubjectsText":{"type":["string","null"]},"open":{"type":"boolean","description":"Open in at least one of the requested months (or, without a month filter, open in some month). Served whatever WINDOW_PUBLIC_VERDICT says."},"verdict":{"anyOf":[{"$ref":"#/components/schemas/Verdict"},{"type":"null"}],"description":"Null when WINDOW_PUBLIC_VERDICT=false (public by default)."},"creative":{"anyOf":[{"type":"object","properties":{"imageConcept":{"type":["string","null"]}},"required":["imageConcept"],"additionalProperties":false},{"type":"null"}],"description":"Null unless WINDOW_PUBLIC_CREATIVE=true. The fine art rating is never served."},"trust":{"$ref":"#/components/schemas/TrustLine"}},"required":["id","title","species","place","locationText","countryText","position","bbox","months","peakWeeksText","peakMonths","behaviour","coatState","habitat","odds","crowds","daysNeeded","notes","operatorsText","backupSubjectsText","open","verdict","creative","trust"],"additionalProperties":false,"description":"A shooting window. Estimated cost is never served."},"TrustLine":{"type":"object","properties":{"confidence":{"anyOf":[{"type":"string","enum":["high","medium","low"]},{"type":"null"}]},"researchDepth":{"anyOf":[{"type":"string","enum":["scan","full"]},{"type":"null"}]},"lastVerified":{"description":"ISO date (YYYY-MM-DD).","type":["string","null"]},"sources":{"type":["string","null"]}},"required":["confidence","researchDepth","lastVerified","sources"],"additionalProperties":false,"description":"Shown on every window: confidence, last checked, sources."},"ListingItem":{"type":"object","properties":{"id":{"type":"string"},"type":{"$ref":"#/components/schemas/ListingType"},"position":{"anyOf":[{"$ref":"#/components/schemas/LngLat"},{"type":"null"}]},"name":{"type":"string"},"thumbUrl":{"description":"Round marker thumbnail.","type":["string","null"]},"tourMode":{"anyOf":[{"$ref":"#/components/schemas/TourMode"},{"type":"null"}],"description":"Tours: picks the pin's icon (boat, plane or safari 4x4), from the listing's tourMode or else its name. Null for other types and for tours the name says nothing about."},"insidePlaceName":{"type":["string","null"]},"distanceToBoundaryM":{"type":["number","null"]},"verdict":{"anyOf":[{"type":"string","enum":["prime","good","acceptable"]},{"type":"null"}],"description":"Best verdict of an open window this listing serves, for the active month filter. Null when WINDOW_PUBLIC_VERDICT=false; \"avoid\" is reported as null."},"faded":{"type":"boolean","description":"True when the month or verdict filter does not match (match=fade). Species and type mismatches are never returned."},"fadeReasons":{"description":"Developer mode only (dev=1 on a server with PBS_DEV_TOOLS): every filter the listing fails.","type":"array","items":{"type":"string","enum":["species","months","type","verdict"]}},"sponsored":{"type":"boolean"},"publicId":{"type":"string"},"slug":{"type":"string"},"path":{"type":"string","description":"Site URL path of the listing page."},"photo":{"anyOf":[{"$ref":"#/components/schemas/Photo"},{"type":"null"}]},"months":{"type":"array","items":{"type":"integer","minimum":1,"maximum":12},"description":"Open months; empty means year round or unknown."},"peakMonths":{"type":"array","items":{"type":"integer","minimum":1,"maximum":12},"description":"Peak months of the windows this listing serves."},"priceFrom":{"type":["number","null"]},"currency":{"type":["string","null"]},"priceUnit":{"anyOf":[{"type":"string","enum":["per_session","per_day","per_night","per_person_per_night","per_person","per_group"]},{"type":"null"}],"description":"What priceFrom is per, read from the listing's own price text: per_session (one hide session), per_day, per_night (a room or hide, however many sleep in it), per_person_per_night, per_person (the whole trip or package), per_group (a private booking). Null when the listing does not say, and always null without a price."},"badge":{"$ref":"#/components/schemas/ParkBadge"},"species":{"type":"array","items":{"$ref":"#/components/schemas/ListingSpeciesRef"}},"speciesHighlight":{"anyOf":[{"$ref":"#/components/schemas/SpeciesHighlight"},{"type":"null"}]},"offroad":{"anyOf":[{"$ref":"#/components/schemas/OffroadRule"},{"type":"null"}],"description":"The off-road driving rule of the park the listing is inside (ADR 0031), with its source; null outside a park or when the park has none."},"ownerState":{"type":"string","enum":["imported","submitted","claimed"]},"verified":{"type":"boolean"},"disclosures":{"type":"object","properties":{"feeding":{"type":["boolean","null"]},"baiting":{"type":["boolean","null"]},"captiveAnimals":{"type":["boolean","null"]}},"required":["feeding","baiting","captiveAnimals"],"additionalProperties":false,"description":"Feeding, baiting and captive animals, shown on every card: true used, false not, null not stated."},"bookingUrl":{"type":["string","null"]},"nextDeparture":{"anyOf":[{"type":"object","properties":{"startDate":{"type":"string"},"endDate":{"type":"string"}},"required":["startDate","endDate"],"additionalProperties":false},{"type":"null"}]},"bestOdds":{"anyOf":[{"$ref":"#/components/schemas/Odds"},{"type":"null"}]},"openWindow":{"type":"boolean","description":"Serves at least one window open in the requested months (any month without a filter)."},"completeness":{"type":"integer","minimum":0,"maximum":5}},"required":["id","type","position","name","thumbUrl","tourMode","insidePlaceName","distanceToBoundaryM","verdict","faded","sponsored","publicId","slug","path","photo","months","peakMonths","priceFrom","currency","priceUnit","badge","species","speciesHighlight","offroad","ownerState","verified","disclosures","bookingUrl","nextDeparture","bestOdds","openWindow","completeness"],"additionalProperties":false},"TourMode":{"type":"string","enum":["safari","boat","flight"],"description":"How a tour gets to the animals (ADR 0035): safari, boat or flight."},"Photo":{"type":"object","properties":{"url":{"type":"string","description":"The image to show. Wikimedia photos point at a rendition at most 960 px wide; load them from the browser, since Wikimedia refuses requests without a User-Agent."},"thumbUrl":{"type":["string","null"]},"alt":{"type":"string"},"width":{"type":["number","null"]},"height":{"type":["number","null"]},"kind":{"type":"string","enum":["photo","logo"]},"credit":{"anyOf":[{"$ref":"#/components/schemas/PhotoCredit"},{"type":"null"}],"description":"Author, licence and source of the photo (Wikimedia Commons today). A photo is only returned once we hold a licence for it and it is credited, so this is set on every photo returned today."}},"required":["url","thumbUrl","alt","width","height","kind","credit"],"additionalProperties":false},"PhotoCredit":{"type":"object","properties":{"title":{"description":"The work's title as its file page gives it; null when none.","type":["string","null"]},"author":{"description":"Null when the file names no author.","type":["string","null"]},"licence":{"type":"string","example":"CC BY-SA 4.0"},"licenceUrl":{"description":"The licence deed, when it has one.","type":["string","null"]},"sourceName":{"type":"string","example":"Wikimedia Commons"},"sourceUrl":{"type":"string","description":"The file's description page."},"text":{"type":"string","example":"Photo: “Arctic fox” by Jane Doe, CC BY-SA 4.0, via Wikimedia Commons","description":"The credit line as plain text; show it (with links) wherever the photo is."}},"required":["title","author","licence","licenceUrl","sourceName","sourceUrl","text"],"additionalProperties":false},"ParkBadge":{"type":"object","properties":{"kind":{"type":"string","enum":["inside","outside","none"]},"text":{"type":"string","example":"Outside, 2 km from Oulanka National Park"},"placeName":{"type":["string","null"]},"path":{"type":["string","null"]},"distanceM":{"type":["number","null"]}},"required":["kind","text","placeName","path","distanceM"],"additionalProperties":false},"ListingSpeciesRef":{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"scientificName":{"type":"string"},"group":{"type":"string","enum":["mammal_terrestrial","mammal_marine","bird_raptor","bird_seabird","bird_other","reptile_amphibian","fish","invertebrate"]},"stripeColour":{"type":["string","null"]},"iucnStatus":{"type":["string","null"]},"path":{"type":"string"},"rating":{"anyOf":[{"$ref":"#/components/schemas/SpeciesRating"},{"type":"null"}]}},"required":["id","publicId","slug","name","scientificName","group","stripeColour","iucnStatus","path","rating"],"additionalProperties":false},"SpeciesRating":{"type":"object","properties":{"rating":{"type":"integer","minimum":1,"maximum":5,"description":"The chance of seeing the species here: 5 excellent, 4 very good, 3 good, 2 fair, 1 poor. Given by the odds when no researched rating exists. A rating of the place for photographs will be a separate field (ADR 0032)."},"label":{"type":"string","enum":["Excellent","Very good","Good","Fair","Poor"]},"odds":{"anyOf":[{"$ref":"#/components/schemas/Odds"},{"type":"null"}],"description":"Chance of seeing it in `months`."},"months":{"type":"array","items":{"type":"integer","minimum":1,"maximum":12},"description":"Months the rating is for; empty means the listing's own months."},"note":{"description":"One short sentence.","type":["string","null"]},"ratedAt":{"description":"ISO date-time it was rated or checked.","type":["string","null"]}},"required":["rating","label","odds","months","note","ratedAt"],"additionalProperties":false,"description":"Per-species rating of a listing (ADR 0032)."},"SpeciesHighlight":{"type":"object","properties":{"id":{"type":"string","description":"The species id."},"slug":{"type":"string"},"name":{"type":"string"},"rating":{"type":"integer","minimum":1,"maximum":5},"label":{"type":"string","enum":["Excellent","Very good","Good","Fair","Poor"]},"months":{"type":"array","items":{"type":"integer","minimum":1,"maximum":12},"description":"The months the rating holds for, sorted; empty when not recorded."},"text":{"type":"string","example":"Brown bear: excellent chance of a sighting (May–Jul)"}},"required":["id","slug","name","rating","label","months","text"],"additionalProperties":false,"description":"The one rated species a card names (ADR 0032): with a species filter, the best rated of the filtered species; without one, the best rated species when it is Very good or better. The rating is the chance of seeing it here."},"OffroadRule":{"type":"object","properties":{"rule":{"type":"string","enum":["allowed","designated_tracks","prohibited","guided_only"]},"headline":{"type":"string","example":"Off-road driving: not allowed."},"detail":{"type":"string","example":"Vehicles stay on marked roads."},"note":{"description":"A short note in the park's own terms.","type":["string","null"]},"checked":{"description":"When the rule was last checked (ISO date).","type":["string","null"]},"source":{"anyOf":[{"$ref":"#/components/schemas/FactSource"},{"type":"null"}]}},"required":["rule","headline","detail","note","checked","source"],"additionalProperties":false,"description":"Whether vehicles may leave the roads in this park (ADR 0031)."},"FactSource":{"type":"object","properties":{"url":{"description":"Link to the source (http or https only).","type":["string","null"]},"title":{"type":"string"},"publisher":{"type":["string","null"]}},"required":["url","title","publisher"],"additionalProperties":false},"FamousResident":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["alive","deceased","unknown"]},"bornYear":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"diedYear":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"statusLine":{"type":"string","description":"Plain words for the card, e.g. \"Died 2022\" or \"Born 2015\"."},"description":{"type":"string","description":"Two or three sentences, reviewed by hand."},"species":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"scientificName":{"type":"string"},"path":{"type":"string"}},"required":["id","slug","name","scientificName","path"],"additionalProperties":false},"place":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"$ref":"#/components/schemas/PlaceKind"},"placePath":{"type":"string"},"path":{"type":"string"}},"required":["id","name","kind","placePath","path"],"additionalProperties":false},"source":{"$ref":"#/components/schemas/FactSource"}},"required":["id","name","status","bornYear","diedYear","statusLine","description","species","place","source"],"additionalProperties":false,"description":"A named animal people travel to see (ADR 0022). Attached to a place of at least 250 km², never to a point: there are no coordinates and no sighting dates."},"SpeciesRangeResponse":{"type":"object","properties":{"slug":{"type":"string"},"range":{"$ref":"#/components/schemas/RangeAvailability"}},"required":["slug","range"],"additionalProperties":false},"PlaceDetail":{"type":"object","properties":{"place":{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"kind":{"$ref":"#/components/schemas/PlaceKind"},"name":{"type":"string"},"slug":{"type":"string"},"placePath":{"type":"string"},"path":{"type":"string"},"governanceClass":{"$ref":"#/components/schemas/GovernanceClass"},"bbox":{"anyOf":[{"$ref":"#/components/schemas/BBox"},{"type":"null"}]},"centroid":{"anyOf":[{"$ref":"#/components/schemas/LngLat"},{"type":"null"}]},"designation":{"type":["string","null"]},"iucnCategory":{"type":["string","null"]},"isoA2":{"type":["string","null"]},"areaKm2":{"type":["number","null"]}},"required":["id","publicId","kind","name","slug","placePath","path","governanceClass","bbox","centroid","designation","iucnCategory","isoA2","areaKm2"],"additionalProperties":false},"ancestors":{"type":"array","items":{"$ref":"#/components/schemas/PlaceRef"}},"children":{"type":"array","items":{"$ref":"#/components/schemas/PlaceRef"}},"windows":{"type":"array","items":{"$ref":"#/components/schemas/Window"}},"byMonth":{"minItems":12,"maxItems":12,"type":"array","items":{"type":"object","properties":{"month":{"type":"integer","minimum":1,"maximum":12},"windowIds":{"type":"array","items":{"type":"string"}}},"required":["month","windowIds"],"additionalProperties":false},"description":"Windows open each month, January to December."},"grid":{"type":"array","items":{"$ref":"#/components/schemas/WindowGridRow"},"description":"Species down, months across."},"species":{"type":"array","items":{"$ref":"#/components/schemas/SpeciesRef"}},"listings":{"type":"array","items":{"$ref":"#/components/schemas/ListingItem"}},"creativeFields":{"type":"boolean"},"famousResidents":{"type":"array","items":{"$ref":"#/components/schemas/FamousResident"},"description":"Reviewed famous animals named by this place (ADR 0022)."},"offroad":{"anyOf":[{"$ref":"#/components/schemas/OffroadRule"},{"type":"null"}]}},"required":["place","ancestors","children","windows","byMonth","grid","species","listings","creativeFields","famousResidents","offroad"],"additionalProperties":false},"GovernanceClass":{"type":"string","enum":["state","private","community","shared","unknown"],"description":"WDPA governance class; drives the stripe colour."},"PlaceRef":{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"kind":{"$ref":"#/components/schemas/PlaceKind"},"name":{"type":"string"},"slug":{"type":"string"},"placePath":{"type":"string"},"path":{"type":"string"},"governanceClass":{"$ref":"#/components/schemas/GovernanceClass"},"bbox":{"anyOf":[{"$ref":"#/components/schemas/BBox"},{"type":"null"}]},"centroid":{"anyOf":[{"$ref":"#/components/schemas/LngLat"},{"type":"null"}]}},"required":["id","publicId","kind","name","slug","placePath","path","governanceClass","bbox","centroid"],"additionalProperties":false},"SpeciesRef":{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"scientificName":{"type":"string"},"group":{"type":"string","enum":["mammal_terrestrial","mammal_marine","bird_raptor","bird_seabird","bird_other","reptile_amphibian","fish","invertebrate"]},"stripeColour":{"type":["string","null"]},"iucnStatus":{"type":["string","null"]},"path":{"type":"string"}},"required":["id","publicId","slug","name","scientificName","group","stripeColour","iucnStatus","path"],"additionalProperties":false},"PlaceConditions":{"type":"object","properties":{"place":{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"name":{"type":"string"},"path":{"type":"string","example":"europe/finland/oulanka"}},"required":["id","publicId","name","path"],"additionalProperties":false},"timeZone":{"type":"string","example":"Europe/Helsinki"},"utcOffset":{"type":"string","description":"Offset now, e.g. \"UTC+2\".","example":"UTC+2"},"generatedAt":{"type":"string","description":"ISO 8601 instant, UTC."},"today":{"$ref":"#/components/schemas/SunDay"},"months":{"minItems":12,"maxItems":12,"type":"array","items":{"$ref":"#/components/schemas/MonthLight"},"description":"The 15th of each month this year."},"weather":{"anyOf":[{"$ref":"#/components/schemas/Weather"},{"type":"null"}],"description":"Null when the weather service is unavailable or switched off. Temperatures are in °C and wind in m/s; clients convert for display."}},"required":["place","timeZone","utcOffset","generatedAt","today","months","weather"],"additionalProperties":false,"description":"Light and weather at the place's centroid."},"SunDay":{"type":"object","properties":{"date":{"type":"string","description":"Local calendar date (YYYY-MM-DD).","example":"2026-06-15"},"state":{"type":"string","enum":["normal","midnight-sun","polar-night"],"description":"midnight-sun: the sun does not set; polar-night: it does not rise."},"solarNoon":{"type":"string","description":"ISO 8601 instant, UTC."},"noonElevation":{"type":"number","description":"Sun height at solar noon as seen (with refraction), degrees. Never below 0 on a day the sun rises; negative in polar night."},"sunrise":{"anyOf":[{"type":"string","description":"ISO 8601 instant, UTC."},{"type":"null"}]},"sunset":{"anyOf":[{"type":"string","description":"ISO 8601 instant, UTC."},{"type":"null"}]},"civilDawn":{"anyOf":[{"type":"string","description":"ISO 8601 instant, UTC."},{"type":"null"}]},"civilDusk":{"anyOf":[{"type":"string","description":"ISO 8601 instant, UTC."},{"type":"null"}]},"dayLengthMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"goldenHour":{"description":"Sun centre between 0 and +6 degrees.","$ref":"#/components/schemas/LightBand"},"blueHour":{"description":"Sun centre between -4 and 0 degrees.","$ref":"#/components/schemas/LightBand"}},"required":["date","state","solarNoon","noonElevation","sunrise","sunset","civilDawn","civilDusk","dayLengthMinutes","goldenHour","blueHour"],"additionalProperties":false},"LightPeriod":{"type":"object","properties":{"start":{"type":"string","description":"ISO 8601 instant, UTC."},"end":{"type":"string","description":"ISO 8601 instant, UTC."},"openStart":{"type":"boolean","description":"Already running at the start of the solar day (from the night before)."},"openEnd":{"type":"boolean","description":"Runs on past the end of the solar day."}},"required":["start","end","openStart","openEnd"],"additionalProperties":false},"LightBand":{"type":"object","properties":{"morning":{"anyOf":[{"$ref":"#/components/schemas/LightPeriod"},{"type":"null"}]},"evening":{"anyOf":[{"$ref":"#/components/schemas/LightPeriod"},{"type":"null"}]},"allDay":{"anyOf":[{"$ref":"#/components/schemas/LightPeriod"},{"type":"null"}],"description":"Set when the sun never leaves the band: one stretch across the middle of the day."}},"required":["morning","evening","allDay"],"additionalProperties":false},"MonthLight":{"type":"object","properties":{"date":{"type":"string","description":"Local calendar date (YYYY-MM-DD).","example":"2026-06-15"},"state":{"type":"string","enum":["normal","midnight-sun","polar-night"],"description":"midnight-sun: the sun does not set; polar-night: it does not rise."},"solarNoon":{"type":"string","description":"ISO 8601 instant, UTC."},"noonElevation":{"type":"number","description":"Sun height at solar noon as seen (with refraction), degrees. Never below 0 on a day the sun rises; negative in polar night."},"sunrise":{"anyOf":[{"type":"string","description":"ISO 8601 instant, UTC."},{"type":"null"}]},"sunset":{"anyOf":[{"type":"string","description":"ISO 8601 instant, UTC."},{"type":"null"}]},"civilDawn":{"anyOf":[{"type":"string","description":"ISO 8601 instant, UTC."},{"type":"null"}]},"civilDusk":{"anyOf":[{"type":"string","description":"ISO 8601 instant, UTC."},{"type":"null"}]},"dayLengthMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"goldenHour":{"description":"Sun centre between 0 and +6 degrees.","$ref":"#/components/schemas/LightBand"},"blueHour":{"description":"Sun centre between -4 and 0 degrees.","$ref":"#/components/schemas/LightBand"},"month":{"type":"integer","minimum":1,"maximum":12}},"required":["date","state","solarNoon","noonElevation","sunrise","sunset","civilDawn","civilDusk","dayLengthMinutes","goldenHour","blueHour","month"],"additionalProperties":false,"description":"The light on the 15th of the month."},"Weather":{"type":"object","properties":{"source":{"type":"string","example":"MET Norway"},"credit":{"type":"string","description":"Show this wherever the weather shows.","example":"Weather: MET Norway"},"creditUrl":{"type":"string"},"updatedAt":{"anyOf":[{"type":"string","description":"ISO 8601 instant, UTC."},{"type":"null"}],"description":"When the forecast was last updated."},"current":{"$ref":"#/components/schemas/WeatherHour"},"next":{"type":"array","items":{"$ref":"#/components/schemas/WeatherHour"},"description":"The next few hours."}},"required":["source","credit","creditUrl","updatedAt","current","next"],"additionalProperties":false},"WeatherHour":{"type":"object","properties":{"time":{"type":"string","description":"ISO 8601 instant, UTC."},"temperatureC":{"type":["number","null"]},"windSpeedMs":{"description":"Metres per second.","type":["number","null"]},"windFromDeg":{"description":"Degrees clockwise from north.","type":["number","null"]},"cloudPercent":{"type":["number","null"]},"humidityPercent":{"type":["number","null"]},"precipitationMm":{"description":"Expected in the hour from `time`.","type":["number","null"]},"summary":{"example":"Partly cloudy","type":["string","null"]}},"required":["time","temperatureC","windSpeedMs","windFromDeg","cloudPercent","humidityPercent","precipitationMm","summary"],"additionalProperties":false},"NationalParksResponse":{"type":"object","properties":{"country":{"anyOf":[{"$ref":"#/components/schemas/PlaceRef"},{"type":"null"}]},"indexPath":{"type":"string","description":"Site URL path of this national parks page."},"parks":{"type":"array","items":{"$ref":"#/components/schemas/NationalParkItem"},"description":"National parks, most listings first, then the biggest."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"National parks there (parks lists up to limit)."},"countries":{"type":"array","items":{"$ref":"#/components/schemas/NationalParkCountry"},"description":"Countries with national parks, by name. Empty when a country is given."}},"required":["country","indexPath","parks","total","countries"],"additionalProperties":false},"NationalParkItem":{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"kind":{"$ref":"#/components/schemas/PlaceKind"},"name":{"type":"string"},"slug":{"type":"string"},"placePath":{"type":"string"},"path":{"type":"string"},"governanceClass":{"$ref":"#/components/schemas/GovernanceClass"},"bbox":{"anyOf":[{"$ref":"#/components/schemas/BBox"},{"type":"null"}]},"centroid":{"anyOf":[{"$ref":"#/components/schemas/LngLat"},{"type":"null"}]},"designation":{"description":"As the source names it.","type":["string","null"]},"areaKm2":{"type":["number","null"]},"listingCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Approved listings in the park, as its list page counts them."}},"required":["id","publicId","kind","name","slug","placePath","path","governanceClass","bbox","centroid","designation","areaKm2","listingCount"],"additionalProperties":false},"NationalParkCountry":{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"kind":{"$ref":"#/components/schemas/PlaceKind"},"name":{"type":"string"},"slug":{"type":"string"},"placePath":{"type":"string"},"path":{"type":"string"},"governanceClass":{"$ref":"#/components/schemas/GovernanceClass"},"bbox":{"anyOf":[{"$ref":"#/components/schemas/BBox"},{"type":"null"}]},"centroid":{"anyOf":[{"$ref":"#/components/schemas/LngLat"},{"type":"null"}]},"parkCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"indexPath":{"type":"string","description":"Site URL path of the country's national parks page, e.g. \"/national-parks/europe/finland\"."}},"required":["id","publicId","kind","name","slug","placePath","path","governanceClass","bbox","centroid","parkCount","indexPath"],"additionalProperties":false},"WindowsResponse":{"type":"object","properties":{"windows":{"type":"array","items":{"$ref":"#/components/schemas/Window"}},"creativeFields":{"type":"boolean"}},"required":["windows","creativeFields"],"additionalProperties":false},"ListingsResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ListingMarkerItem"}},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"debug":{"description":"Developer mode only (dev=1 on a server with PBS_DEV_TOOLS).","type":"object","properties":{"hidden":{"type":"array","items":{"$ref":"#/components/schemas/HiddenListing"}}},"required":["hidden"],"additionalProperties":false}},"required":["items","total"],"additionalProperties":false},"ListingMarkerItem":{"type":"object","properties":{"id":{"type":"string"},"type":{"$ref":"#/components/schemas/ListingType"},"position":{"$ref":"#/components/schemas/LngLat"},"name":{"type":"string"},"thumbUrl":{"description":"Round marker thumbnail.","type":["string","null"]},"tourMode":{"anyOf":[{"$ref":"#/components/schemas/TourMode"},{"type":"null"}],"description":"Tours: picks the pin's icon (boat, plane or safari 4x4), from the listing's tourMode or else its name. Null for other types and for tours the name says nothing about."},"insidePlaceName":{"type":["string","null"]},"distanceToBoundaryM":{"type":["number","null"]},"verdict":{"anyOf":[{"type":"string","enum":["prime","good","acceptable"]},{"type":"null"}],"description":"Best verdict of an open window this listing serves, for the active month filter. Null when WINDOW_PUBLIC_VERDICT=false; \"avoid\" is reported as null."},"faded":{"type":"boolean","description":"True when the month or verdict filter does not match (match=fade). Species and type mismatches are never returned."},"fadeReasons":{"description":"Developer mode only (dev=1 on a server with PBS_DEV_TOOLS): every filter the listing fails.","type":"array","items":{"type":"string","enum":["species","months","type","verdict"]}},"sponsored":{"type":"boolean"},"publicId":{"type":"string"},"slug":{"type":"string"},"path":{"type":"string","description":"Site URL path of the listing page."},"photo":{"anyOf":[{"$ref":"#/components/schemas/Photo"},{"type":"null"}]},"months":{"type":"array","items":{"type":"integer","minimum":1,"maximum":12},"description":"Open months; empty means year round or unknown."},"peakMonths":{"type":"array","items":{"type":"integer","minimum":1,"maximum":12},"description":"Peak months of the windows this listing serves."},"priceFrom":{"type":["number","null"]},"currency":{"type":["string","null"]},"priceUnit":{"anyOf":[{"type":"string","enum":["per_session","per_day","per_night","per_person_per_night","per_person","per_group"]},{"type":"null"}],"description":"What priceFrom is per, read from the listing's own price text: per_session (one hide session), per_day, per_night (a room or hide, however many sleep in it), per_person_per_night, per_person (the whole trip or package), per_group (a private booking). Null when the listing does not say, and always null without a price."},"badge":{"$ref":"#/components/schemas/ParkBadge"},"species":{"type":"array","items":{"$ref":"#/components/schemas/ListingSpeciesRef"}},"speciesHighlight":{"anyOf":[{"$ref":"#/components/schemas/SpeciesHighlight"},{"type":"null"}]},"offroad":{"anyOf":[{"$ref":"#/components/schemas/OffroadRule"},{"type":"null"}],"description":"The off-road driving rule of the park the listing is inside (ADR 0031), with its source; null outside a park or when the park has none."},"ownerState":{"type":"string","enum":["imported","submitted","claimed"]},"verified":{"type":"boolean"},"disclosures":{"type":"object","properties":{"feeding":{"type":["boolean","null"]},"baiting":{"type":["boolean","null"]},"captiveAnimals":{"type":["boolean","null"]}},"required":["feeding","baiting","captiveAnimals"],"additionalProperties":false,"description":"Feeding, baiting and captive animals, shown on every card: true used, false not, null not stated."},"bookingUrl":{"type":["string","null"]},"nextDeparture":{"anyOf":[{"type":"object","properties":{"startDate":{"type":"string"},"endDate":{"type":"string"}},"required":["startDate","endDate"],"additionalProperties":false},{"type":"null"}]},"bestOdds":{"anyOf":[{"$ref":"#/components/schemas/Odds"},{"type":"null"}]},"openWindow":{"type":"boolean","description":"Serves at least one window open in the requested months (any month without a filter)."},"completeness":{"type":"integer","minimum":0,"maximum":5}},"required":["id","type","position","name","thumbUrl","tourMode","insidePlaceName","distanceToBoundaryM","verdict","faded","sponsored","publicId","slug","path","photo","months","peakMonths","priceFrom","currency","priceUnit","badge","species","speciesHighlight","offroad","ownerState","verified","disclosures","bookingUrl","nextDeparture","bestOdds","openWindow","completeness"],"additionalProperties":false},"HiddenListing":{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"name":{"type":"string"},"type":{"$ref":"#/components/schemas/ListingType"},"position":{"$ref":"#/components/schemas/LngLat"},"path":{"type":"string"},"species":{"type":"array","items":{"type":"string"},"description":"Names of the linked species."},"speciesText":{"type":"array","items":{"type":"string"},"description":"Species names the importer could not match to a species (species_text)."},"fadeReasons":{"type":"array","items":{"type":"string","enum":["species","months","type","verdict"]}}},"required":["id","publicId","name","type","position","path","species","speciesText","fadeReasons"],"additionalProperties":false},"MarkersResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/MarkerItem"}},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"debug":{"description":"Developer mode only (dev=1 on a server with PBS_DEV_TOOLS).","type":"object","properties":{"hidden":{"type":"array","items":{"$ref":"#/components/schemas/HiddenListing"}}},"required":["hidden"],"additionalProperties":false}},"required":["items","total"],"additionalProperties":false},"MarkerItem":{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"type":{"$ref":"#/components/schemas/ListingType"},"position":{"$ref":"#/components/schemas/LngLat"},"name":{"type":"string"},"thumbUrl":{"description":"Round marker thumbnail.","type":["string","null"]},"tourMode":{"anyOf":[{"$ref":"#/components/schemas/TourMode"},{"type":"null"}],"description":"Tours: picks the pin's icon (boat, plane or safari 4x4), from the listing's tourMode or else its name. Null for other types and for tours the name says nothing about."},"insidePlaceName":{"type":["string","null"]},"distanceToBoundaryM":{"type":["number","null"]},"verdict":{"anyOf":[{"type":"string","enum":["prime","good","acceptable"]},{"type":"null"}],"description":"Best verdict of an open window this listing serves, for the active month filter. Null when WINDOW_PUBLIC_VERDICT=false; \"avoid\" is reported as null."},"faded":{"type":"boolean","description":"True when the month or verdict filter does not match (match=fade). Species and type mismatches are never returned."},"fadeReasons":{"description":"Developer mode only (dev=1 on a server with PBS_DEV_TOOLS): every filter the listing fails.","type":"array","items":{"type":"string","enum":["species","months","type","verdict"]}},"sponsored":{"type":"boolean"}},"required":["id","publicId","type","position","name","thumbUrl","tourMode","insidePlaceName","distanceToBoundaryM","verdict","faded","sponsored"],"additionalProperties":false},"AlongResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AlongItem"},"description":"Nearest the route first."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Matches in the whole corridor."},"km":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"months":{"type":"array","items":{"type":"integer","minimum":1,"maximum":12},"description":"The trip's months used as the filter; empty without dates."}},"required":["items","total","km","months"],"additionalProperties":false},"AlongItem":{"type":"object","properties":{"id":{"type":"string"},"type":{"$ref":"#/components/schemas/ListingType"},"position":{"$ref":"#/components/schemas/LngLat"},"name":{"type":"string"},"thumbUrl":{"description":"Round marker thumbnail.","type":["string","null"]},"tourMode":{"anyOf":[{"$ref":"#/components/schemas/TourMode"},{"type":"null"}],"description":"Tours: picks the pin's icon (boat, plane or safari 4x4), from the listing's tourMode or else its name. Null for other types and for tours the name says nothing about."},"insidePlaceName":{"type":["string","null"]},"distanceToBoundaryM":{"type":["number","null"]},"verdict":{"anyOf":[{"type":"string","enum":["prime","good","acceptable"]},{"type":"null"}],"description":"Best verdict of an open window this listing serves, for the active month filter. Null when WINDOW_PUBLIC_VERDICT=false; \"avoid\" is reported as null."},"faded":{"type":"boolean","description":"True when the month or verdict filter does not match (match=fade). Species and type mismatches are never returned."},"fadeReasons":{"description":"Developer mode only (dev=1 on a server with PBS_DEV_TOOLS): every filter the listing fails.","type":"array","items":{"type":"string","enum":["species","months","type","verdict"]}},"sponsored":{"type":"boolean"},"publicId":{"type":"string"},"slug":{"type":"string"},"path":{"type":"string","description":"Site URL path of the listing page."},"photo":{"anyOf":[{"$ref":"#/components/schemas/Photo"},{"type":"null"}]},"months":{"type":"array","items":{"type":"integer","minimum":1,"maximum":12},"description":"Open months; empty means year round or unknown."},"peakMonths":{"type":"array","items":{"type":"integer","minimum":1,"maximum":12},"description":"Peak months of the windows this listing serves."},"priceFrom":{"type":["number","null"]},"currency":{"type":["string","null"]},"priceUnit":{"anyOf":[{"type":"string","enum":["per_session","per_day","per_night","per_person_per_night","per_person","per_group"]},{"type":"null"}],"description":"What priceFrom is per, read from the listing's own price text: per_session (one hide session), per_day, per_night (a room or hide, however many sleep in it), per_person_per_night, per_person (the whole trip or package), per_group (a private booking). Null when the listing does not say, and always null without a price."},"badge":{"$ref":"#/components/schemas/ParkBadge"},"species":{"type":"array","items":{"$ref":"#/components/schemas/ListingSpeciesRef"}},"speciesHighlight":{"anyOf":[{"$ref":"#/components/schemas/SpeciesHighlight"},{"type":"null"}]},"offroad":{"anyOf":[{"$ref":"#/components/schemas/OffroadRule"},{"type":"null"}],"description":"The off-road driving rule of the park the listing is inside (ADR 0031), with its source; null outside a park or when the park has none."},"ownerState":{"type":"string","enum":["imported","submitted","claimed"]},"verified":{"type":"boolean"},"disclosures":{"type":"object","properties":{"feeding":{"type":["boolean","null"]},"baiting":{"type":["boolean","null"]},"captiveAnimals":{"type":["boolean","null"]}},"required":["feeding","baiting","captiveAnimals"],"additionalProperties":false,"description":"Feeding, baiting and captive animals, shown on every card: true used, false not, null not stated."},"bookingUrl":{"type":["string","null"]},"nextDeparture":{"anyOf":[{"type":"object","properties":{"startDate":{"type":"string"},"endDate":{"type":"string"}},"required":["startDate","endDate"],"additionalProperties":false},{"type":"null"}]},"bestOdds":{"anyOf":[{"$ref":"#/components/schemas/Odds"},{"type":"null"}]},"openWindow":{"type":"boolean","description":"Serves at least one window open in the requested months (any month without a filter)."},"completeness":{"type":"integer","minimum":0,"maximum":5},"distanceKm":{"type":"number","description":"Kilometres from the listing to the nearest part of the route, one decimal."}},"required":["id","type","position","name","thumbUrl","tourMode","insidePlaceName","distanceToBoundaryM","verdict","faded","sponsored","publicId","slug","path","photo","months","peakMonths","priceFrom","currency","priceUnit","badge","species","speciesHighlight","offroad","ownerState","verified","disclosures","bookingUrl","nextDeparture","bestOdds","openWindow","completeness","distanceKm"],"additionalProperties":false},"ListingDetail":{"type":"object","properties":{"id":{"type":"string"},"type":{"$ref":"#/components/schemas/ListingType"},"position":{"anyOf":[{"$ref":"#/components/schemas/LngLat"},{"type":"null"}]},"name":{"type":"string"},"thumbUrl":{"description":"Round marker thumbnail.","type":["string","null"]},"tourMode":{"anyOf":[{"$ref":"#/components/schemas/TourMode"},{"type":"null"}],"description":"Tours: picks the pin's icon (boat, plane or safari 4x4), from the listing's tourMode or else its name. Null for other types and for tours the name says nothing about."},"insidePlaceName":{"type":["string","null"]},"distanceToBoundaryM":{"type":["number","null"]},"verdict":{"anyOf":[{"type":"string","enum":["prime","good","acceptable"]},{"type":"null"}],"description":"Best verdict of an open window this listing serves, for the active month filter. Null when WINDOW_PUBLIC_VERDICT=false; \"avoid\" is reported as null."},"faded":{"type":"boolean","description":"True when the month or verdict filter does not match (match=fade). Species and type mismatches are never returned."},"fadeReasons":{"description":"Developer mode only (dev=1 on a server with PBS_DEV_TOOLS): every filter the listing fails.","type":"array","items":{"type":"string","enum":["species","months","type","verdict"]}},"sponsored":{"type":"boolean"},"publicId":{"type":"string"},"slug":{"type":"string"},"path":{"type":"string","description":"Site URL path of the listing page."},"photo":{"anyOf":[{"$ref":"#/components/schemas/Photo"},{"type":"null"}]},"months":{"type":"array","items":{"type":"integer","minimum":1,"maximum":12},"description":"Open months; empty means year round or unknown."},"peakMonths":{"type":"array","items":{"type":"integer","minimum":1,"maximum":12},"description":"Peak months of the windows this listing serves."},"priceFrom":{"type":["number","null"]},"currency":{"type":["string","null"]},"priceUnit":{"anyOf":[{"type":"string","enum":["per_session","per_day","per_night","per_person_per_night","per_person","per_group"]},{"type":"null"}],"description":"What priceFrom is per, read from the listing's own price text: per_session (one hide session), per_day, per_night (a room or hide, however many sleep in it), per_person_per_night, per_person (the whole trip or package), per_group (a private booking). Null when the listing does not say, and always null without a price."},"badge":{"$ref":"#/components/schemas/ParkBadge"},"species":{"type":"array","items":{"$ref":"#/components/schemas/ListingSpeciesRefWithLens"},"description":"Target species with their rating at this listing and lens advice. The listing's own details.focalLengthMm, when present, is the advice for this place."},"speciesHighlight":{"anyOf":[{"$ref":"#/components/schemas/SpeciesHighlight"},{"type":"null"}]},"offroad":{"anyOf":[{"$ref":"#/components/schemas/OffroadRule"},{"type":"null"}],"description":"The off-road driving rule of the park the listing is inside (ADR 0031), with its source; null outside a park or when the park has none."},"ownerState":{"type":"string","enum":["imported","submitted","claimed"]},"verified":{"type":"boolean"},"disclosures":{"type":"object","properties":{"feeding":{"type":["boolean","null"]},"baiting":{"type":["boolean","null"]},"captiveAnimals":{"type":["boolean","null"]}},"required":["feeding","baiting","captiveAnimals"],"additionalProperties":false,"description":"Feeding, baiting and captive animals, shown on every card: true used, false not, null not stated."},"bookingUrl":{"type":["string","null"]},"nextDeparture":{"anyOf":[{"type":"object","properties":{"startDate":{"type":"string"},"endDate":{"type":"string"}},"required":["startDate","endDate"],"additionalProperties":false},{"type":"null"}]},"bestOdds":{"anyOf":[{"$ref":"#/components/schemas/Odds"},{"type":"null"}]},"openWindow":{"type":"boolean","description":"Serves at least one window open in the requested months (any month without a filter)."},"completeness":{"type":"integer","minimum":0,"maximum":5},"description":{"type":["string","null"]},"photos":{"type":"array","items":{"$ref":"#/components/schemas/Photo"}},"details":{"$ref":"#/components/schemas/ListingDetails"},"organisation":{"anyOf":[{"type":"object","properties":{"name":{"type":"string"},"websiteUrl":{"type":["string","null"]},"claimed":{"type":"boolean"}},"required":["name","websiteUrl","claimed"],"additionalProperties":false},{"type":"null"}]},"containingPlace":{"anyOf":[{"$ref":"#/components/schemas/PlaceRef"},{"type":"null"}]},"nearestPlace":{"anyOf":[{"$ref":"#/components/schemas/PlaceRef"},{"type":"null"}]},"nearestAirport":{"anyOf":[{"$ref":"#/components/schemas/NearestAirport"},{"type":"null"}]},"departures":{"type":"array","items":{"type":"object","properties":{"startDate":{"type":"string"},"endDate":{"type":"string"},"price":{"type":["number","null"]},"currency":{"type":["string","null"]},"seatsLeft":{"type":["number","null"]},"status":{"type":"string"},"bookingUrl":{"type":["string","null"]}},"required":["startDate","endDate","price","currency","seatsLeft","status","bookingUrl"],"additionalProperties":false}},"windows":{"type":"array","items":{"$ref":"#/components/schemas/Window"}},"lastCheckedAt":{"description":"ISO timestamp.","type":["string","null"]},"priceNote":{"type":"string","description":"Prices are in the operator's currency; conversions are approximate."}},"required":["id","type","position","name","thumbUrl","tourMode","insidePlaceName","distanceToBoundaryM","verdict","faded","sponsored","publicId","slug","path","photo","months","peakMonths","priceFrom","currency","priceUnit","badge","species","speciesHighlight","offroad","ownerState","verified","disclosures","bookingUrl","nextDeparture","bestOdds","openWindow","completeness","description","photos","details","organisation","containingPlace","nearestPlace","nearestAirport","departures","windows","lastCheckedAt","priceNote"],"additionalProperties":false},"ListingSpeciesRefWithLens":{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"scientificName":{"type":"string"},"group":{"type":"string","enum":["mammal_terrestrial","mammal_marine","bird_raptor","bird_seabird","bird_other","reptile_amphibian","fish","invertebrate"]},"stripeColour":{"type":["string","null"]},"iucnStatus":{"type":["string","null"]},"path":{"type":"string"},"rating":{"anyOf":[{"$ref":"#/components/schemas/SpeciesRating"},{"type":"null"}]},"lens":{"anyOf":[{"$ref":"#/components/schemas/SpeciesLens"},{"type":"null"}],"description":"Null when there is no lens advice."}},"required":["id","publicId","slug","name","scientificName","group","stripeColour","iucnStatus","path","rating","lens"],"additionalProperties":false},"ListingDetails":{"type":"object","properties":{"feeding":{"description":"Animals are fed.","type":"boolean"},"baiting":{"description":"Bait is used.","type":"boolean"},"captiveAnimals":{"description":"Captive animals are used.","type":"boolean"},"includes":{"description":"What the price covers.","type":"array","items":{"$ref":"#/components/schemas/Inclusion"}},"excludes":{"description":"What the price leaves out (meals extra, flights not included).","type":"array","items":{"$ref":"#/components/schemas/Inclusion"}},"includesText":{"description":"The wording includes and excludes were read from.","type":"string","minLength":1},"difficulty":{"$ref":"#/components/schemas/Difficulty"},"languages":{"description":"Languages the guides or hosts speak, as ISO 639-1 codes. English unless the listing states otherwise; to be reviewed.","example":["en"],"type":"array","items":{"type":"string","description":"ISO 639-1 code, lower case.","example":"en"}},"hideStyle":{"description":"Usually one of ground, elevated, floating, underground, mobile, boat, other; older imports may carry another word.","type":"string","minLength":1},"sessionLengthHours":{"type":"number","minimum":0},"capacity":{"description":"Photographers per session.","type":"integer","minimum":0,"maximum":9007199254740991},"overnight":{"type":"boolean"},"focalLengthMm":{"description":"Focal length to bring, full-frame equivalent; no max means \"or longer\".","type":"object","properties":{"min":{"type":"number","minimum":0},"max":{"type":"number","minimum":0}},"required":["min"],"additionalProperties":false},"subjectDistanceM":{"description":"How far the animals usually are, in metres.","type":"object","properties":{"min":{"type":"number","minimum":0},"max":{"type":"number","minimum":0}},"required":["min"],"additionalProperties":false},"photographyFeatures":{"type":"object","properties":{"hidesOnSite":{"type":"boolean"},"photoVehicles":{"type":"boolean"},"powerAndCharging":{"type":"boolean"},"internet":{"type":"boolean"}},"additionalProperties":false},"speciesNearby":{"type":"array","items":{"type":"string","minLength":1}},"leaders":{"type":"array","items":{"type":"string","minLength":1}},"tourMode":{"description":"Tours: how the tour travels, when the listing says. The pin's `tourMode` falls back to the name.","$ref":"#/components/schemas/TourMode"},"startPlace":{"type":"string","minLength":1},"startCoordinates":{"description":"Departure port of a voyage pinned at its destination.","type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"],"additionalProperties":false},"endPlace":{"type":"string","minLength":1},"endCoordinates":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"],"additionalProperties":false},"itineraryPlaces":{"type":"array","items":{"type":"string","minLength":1}},"groupSize":{"type":"integer","minimum":0,"maximum":9007199254740991},"durationDays":{"type":"number","minimum":0},"cityOrPlace":{"type":"string","minLength":1},"genre":{"type":"string","minLength":1},"skillLevel":{"type":"string","minLength":1},"person":{"type":"string","minLength":1},"baseArea":{"type":"string","minLength":1},"vehicleOrHideAccess":{"type":"string","minLength":1},"dayRateFrom":{"description":"In the listing's currency.","type":"number","minimum":0}},"additionalProperties":false,"description":"Per-type fields; only the keys a listing has are present."},"Inclusion":{"type":"string","enum":["accommodation","meals","drinks","transfers","flights","guiding","activities","equipment_hire","park_fees","hide_fee","taxes","tips","insurance"],"description":"Something a price covers or leaves out."},"Difficulty":{"type":"string","enum":["easy","moderate","demanding"],"description":"How physically demanding the listing is: easy, moderate or demanding."},"NearestAirport":{"type":"object","properties":{"name":{"type":"string","example":"Kajaani Airport"},"iataCode":{"type":"string","example":"KAJ"},"municipality":{"type":["string","null"]},"countryCode":{"type":"string","description":"ISO 3166-1 alpha-2.","example":"FI"},"distanceM":{"type":"number","description":"Straight-line (geodesic) distance in metres; not a driving distance."},"from":{"type":"string","enum":["listing","tour_start"],"description":"What the distance is measured from: the listing's point, or a tour's start."},"label":{"type":"string","example":"Nearest airport","description":"Shown before `text`; for a tour, \"Nearest airport to the start (Ushuaia)\"."},"text":{"type":"string","example":"Kajaani Airport (KAJ), 90 km in a straight line"}},"required":["name","iataCode","municipality","countryCode","distanceM","from","label","text"],"additionalProperties":false,"description":"The nearest airport with scheduled flights within 500 km (OurAirports): of a tour's start coordinates for tours (null when a tour has none), else of the listing."},"ListingConditions":{"type":"object","properties":{"listing":{"type":"object","properties":{"id":{"type":"string"},"publicId":{"type":"string"},"name":{"type":"string"}},"required":["id","publicId","name"],"additionalProperties":false},"timeZone":{"type":"string","example":"Europe/Helsinki"},"utcOffset":{"type":"string","description":"Offset now, e.g. \"UTC+2\".","example":"UTC+2"},"generatedAt":{"type":"string","description":"ISO 8601 instant, UTC."},"today":{"$ref":"#/components/schemas/SunDay"},"months":{"minItems":12,"maxItems":12,"type":"array","items":{"$ref":"#/components/schemas/MonthLight"},"description":"The 15th of each month this year."},"weather":{"anyOf":[{"$ref":"#/components/schemas/Weather"},{"type":"null"}],"description":"Null when the weather service is unavailable or switched off. Temperatures are in °C and wind in m/s; clients convert for display."}},"required":["listing","timeZone","utcOffset","generatedAt","today","months","weather"],"additionalProperties":false},"InSeason":{"type":"object","properties":{"place":{"$ref":"#/components/schemas/PlaceRef"},"fallback":{"type":"boolean"},"month":{"type":"integer","minimum":1,"maximum":12},"openWindowCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"topSpecies":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"path":{"type":"string"}},"required":["slug","name","path"],"additionalProperties":false}},"line":{"type":"string","example":"In season in Finland this October: brown bear, eurasian lynx"},"markers":{"type":"array","items":{"$ref":"#/components/schemas/ListingMarkerItem"}}},"required":["place","fallback","month","openWindowCount","topSpecies","line","markers"],"additionalProperties":false,"description":"Opening sequence: where to frame and what is in season."},"RatesResponse":{"type":"object","properties":{"base":{"type":"string","const":"EUR"},"date":{"type":"string","description":"Day the rates were published for (ISO date)."},"rates":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"number"},"description":"Units of each currency per 1 EUR. EUR itself is implied."},"source":{"type":"string","example":"European Central Bank reference rates"}},"required":["base","date","rates","source"],"additionalProperties":false,"description":"Reference rates for approximate price conversion only; operators charge in their own currency."},"FeedbackResponse":{"type":"object","properties":{"ok":{"type":"boolean","const":true}},"required":["ok"],"additionalProperties":false,"description":"The message was received."}}}}