{"openapi":"3.1.0","info":{"title":"Levin Hiihtogreeni booking API","version":"1.0.0","summary":"Prices, availability and booking requests for Levin Hiihtogreeni, a two-apartment cabin for groups by the Levi slopes and golf course (Finnish Lapland).","description":"Prices are per apartment and include VAT. A full Saturday-to-Saturday week costs the weekly price; every other night costs the nightly price. Each apartment pays final cleaning once per stay; bed linen and towels are optional and priced per guest. Booking both apartments (the whole house) includes the 20-person conference room. Read endpoints are public and CORS-open. Booking is by request: POST /api/v1/hiihtogreeni/inquiries records a pending booking that holds the dates while the owner replies by email. No payment is taken through this API. Prices and availability are live from the owner's booking system; never quote a price that /quote has not returned. The same operations are available as MCP tools (Streamable HTTP) at https://cabins.levifinland.fi/mcp.","contact":{"name":"Levin Hiihtogreeni Oy","email":"info@levifinland.fi","url":"https://www.hiihtogreeni.fi"},"termsOfService":"https://cabins.levifinland.fi/en/hiihtogreeni/terms"},"servers":[{"url":"https://cabins.levifinland.fi"}],"paths":{"/api/v1/hiihtogreeni/property":{"get":{"operationId":"getProperty","summary":"Property description: apartments, capacity, rooms, amenities, distances, house rules, contact, price summary and how booking works.","parameters":[{"name":"lang","in":"query","schema":{"type":"string","enum":["en","fi","de","fr","nl"]},"description":"Language of the human-readable strings."}],"responses":{"200":{"description":"Property document","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/v1/hiihtogreeni/pricing":{"get":{"operationId":"getPricing","summary":"Seasons with the weekly (Saturday to Saturday) and nightly price per apartment, extras, stay and payment rules, and the last-minute offer.","responses":{"200":{"description":"Pricing document","content":{"application/json":{"schema":{"type":"object"}}}},"503":{"description":"Booking system unreachable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/hiihtogreeni/availability":{"get":{"operationId":"getAvailability","summary":"Each night per apartment and room, with prices for free nights (default: 180 nights from today, at most 400).","parameters":[{"name":"from","in":"query","schema":{"type":"string","format":"date","example":"2027-02-20"},"description":"First night (default today)."},{"name":"to","in":"query","schema":{"type":"string","format":"date","example":"2027-02-20"},"description":"Exclusive end date."}],"responses":{"200":{"description":"Nights","content":{"application/json":{"schema":{"type":"object","properties":{"nights":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","format":"date","example":"2027-02-20"},"saturday":{"type":"boolean"},"apartment_a":{"$ref":"#/components/schemas/ApartmentNight"},"apartment_b":{"$ref":"#/components/schemas/ApartmentNight"},"conference_room":{"$ref":"#/components/schemas/NightStatus"},"maintenance_room":{"$ref":"#/components/schemas/NightStatus"}}}},"rules":{"type":"object"},"last_minute":{"type":["object","null"]}}}}}},"400":{"description":"Bad dates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Booking system unreachable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/hiihtogreeni/quote":{"get":{"operationId":"getQuote","summary":"The exact price of a stay, line by line, as the booking calendar shows it. Validates the stay rules and availability.","parameters":[{"name":"check_in","in":"query","required":true,"schema":{"type":"string","format":"date","example":"2027-02-20"}},{"name":"check_out","in":"query","required":true,"schema":{"type":"string","format":"date","example":"2027-02-20"},"description":"Departure date (the last night is the day before)."},{"name":"units","in":"query","required":true,"schema":{"type":"string","enum":["A","B","AB"]},"description":"Apartment A, apartment B, or AB for the whole house. Each apartment sleeps 14; the whole house 28."},{"name":"guests","in":"query","schema":{"type":"integer","minimum":1,"maximum":28,"default":2},"description":"Total guests; split evenly for AB."},{"name":"guests_a","in":"query","schema":{"type":"integer","minimum":0,"maximum":14},"description":"Guests in apartment A (instead of guests)."},{"name":"guests_b","in":"query","schema":{"type":"integer","minimum":0,"maximum":14},"description":"Guests in apartment B (instead of guests)."},{"name":"bed_linen_and_towels","in":"query","schema":{"type":"boolean","default":true},"description":"Linen and towels for every guest (priced per guest)."},{"name":"beds_made","in":"query","schema":{"type":"boolean","default":false},"description":"Made-up beds, on top of linen."},{"name":"conference_room","in":"query","schema":{"type":"boolean","default":false},"description":"The 20-person conference room; included free with AB."},{"name":"maintenance_room","in":"query","schema":{"type":"boolean","default":false},"description":"The warm ski and equipment maintenance room."},{"name":"lang","in":"query","schema":{"type":"string","enum":["en","fi","de","fr","nl"]}}],"responses":{"200":{"description":"Quote","content":{"application/json":{"schema":{"type":"object","properties":{"quote":{"$ref":"#/components/schemas/Quote"},"saturday_suggestion":{"type":["object","null"]},"note":{"type":"string"}}}}}},"400":{"description":"Malformed parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Dates unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Rule violation (minimum stay, booking window, guests, no price)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Booking system unreachable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/hiihtogreeni/inquiries":{"post":{"operationId":"createInquiry","summary":"Send a booking request for a guest who has agreed to it. Records a pending booking that holds the dates for 5 days, emails the owner and a confirmation to the guest. Not binding; nothing is charged. Rate limited.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InquiryRequest"}}}},"responses":{"201":{"description":"Recorded","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"pending"},"reference":{"type":"string","example":"HG-7KQ2M9XA"},"quote":{"$ref":"#/components/schemas/Quote"},"next_steps":{"type":"string"},"terms_url":{"type":"string"},"terms_version":{"type":"string"}}}}}},"400":{"description":"Malformed body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Dates unavailable, or price_changed (detail.quote has the current price)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation failed (terms_not_accepted, invalid_contact, a stay rule)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Booking requests not open, or booking system unreachable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"schemas":{"Error":{"type":"object","required":["error","message"],"properties":{"error":{"type":"string","enum":["invalid_request","invalid_json","invalid_dates","invalid_units","invalid_guests","check_in_in_past","outside_booking_window","below_minimum_stay","above_maximum_stay","dates_unavailable","no_price_for_dates","price_changed","terms_not_accepted","invalid_contact","inquiries_closed","rate_limited","booking_source_unavailable","internal_error"],"description":"Stable machine-readable code"},"message":{"type":"string"},"detail":{"type":"object","additionalProperties":true}}},"NightStatus":{"type":"string","enum":["available","unavailable","no_price","past","outside_booking_window"]},"ApartmentNight":{"type":"object","properties":{"status":{"$ref":"#/components/schemas/NightStatus"},"nightly_eur":{"type":"number","description":"Present when available"},"weekly_eur":{"type":"number","description":"A full Saturday-to-Saturday week in this night's season"}}},"Quote":{"type":"object","properties":{"check_in":{"type":"string","format":"date","example":"2027-02-20"},"check_out":{"type":"string","format":"date","example":"2027-02-20"},"nights":{"type":"integer"},"units":{"type":"string","enum":["A","B","AB"]},"guests":{"type":"object","properties":{"apartment_a":{"type":"integer"},"apartment_b":{"type":"integer"}}},"currency":{"type":"string","example":"EUR"},"prices_include_vat":{"type":"boolean"},"lines":{"type":"array","items":{"type":"object","properties":{"item":{"type":"string","example":"apartment_a"},"description":{"type":"string"},"quantity":{"type":"integer"},"unit":{"type":"string","enum":["week","night","stay","person"]},"unit_price_eur":{"type":"number"},"total_eur":{"type":"number"},"included":{"type":"boolean"},"percent":{"type":"number","description":"On the last-minute discount line"}}}},"vat_eur":{"type":"number"},"total_eur":{"type":"number"}}},"InquiryRequest":{"type":"object","required":["check_in","check_out","units","name","email","terms_accepted"],"properties":{"check_in":{"type":"string","format":"date","example":"2027-02-20"},"check_out":{"type":"string","format":"date","example":"2027-02-20"},"units":{"type":"string","enum":["A","B","AB"],"description":"Apartment A, apartment B, or AB for the whole house. Each apartment sleeps 14; the whole house 28."},"guests":{"type":"integer","minimum":1,"maximum":28,"default":2,"description":"Total guests; split evenly for AB."},"guests_a":{"type":"integer","minimum":0,"maximum":14,"description":"Guests in apartment A (instead of guests)."},"guests_b":{"type":"integer","minimum":0,"maximum":14,"description":"Guests in apartment B (instead of guests)."},"bed_linen_and_towels":{"type":"boolean","default":true,"description":"Linen and towels for every guest (priced per guest)."},"beds_made":{"type":"boolean","default":false,"description":"Made-up beds, on top of linen."},"conference_room":{"type":"boolean","default":false,"description":"The 20-person conference room; included free with AB."},"maintenance_room":{"type":"boolean","default":false,"description":"The warm ski and equipment maintenance room."},"name":{"type":"string","maxLength":200},"email":{"type":"string","format":"email","description":"The owner replies here."},"phone":{"type":"string","maxLength":50},"message":{"type":"string","maxLength":4500,"description":"Arrival time, the group, special wishes."},"locale":{"type":"string","enum":["en","fi","de","fr","nl"],"description":"Language of the guest's confirmation email."},"marketing_consent":{"type":"boolean","default":false},"terms_accepted":{"type":"boolean","description":"Must be true: the guest has read https://cabins.levifinland.fi/en/hiihtogreeni/terms"},"expected_total_eur":{"type":"number","description":"total_eur from /quote; if the price has changed, nothing is saved and 409 price_changed is returned."},"source":{"type":"string","maxLength":100,"description":"Name of the agent or app sending on the guest's behalf.","example":"Claude"}}}}}}