{"openapi":"3.1.0","info":{"title":"Yeww availability","version":"1.0.0","summary":"Live private lesson availability. No authentication.","description":"Search public ski, snowboard, and mountain-bike sessions on Yeww. The response is the availability at the time of the request. It does not hold a session. The booking page checks the session again. Authentication is not required."},"servers":[{"url":"https://yeww.app"}],"paths":{"/api/availability":{"get":{"operationId":"searchAvailability","summary":"Search live availability","description":"Authentication is not required. No API key, cookie, or Authorization header. Send no request body. sport is required. Send date, or send both from and to. Do not send date together with from or to. Dates are Europe/Paris calendar days, from today through 365 days ahead. from and to are inclusive and at most 14 days. A query that matches nothing is HTTP 200 with an empty offers array. At most 100 offers are returned. truncated is true when more matched. Offers that would share one booking URL are omitted. price is the final customer charge: the instructor take-home plus a 10% Yeww fee. An instructor price of 15000 cents is charged as 165.00. Responses use Cache-Control: no-store and allow any browser origin. Example: https://yeww.app/api/availability?sport=snowboard&date=2026-12-27&resort=Morzine. That URL does not promise a free session.","security":[],"parameters":[{"name":"sport","in":"query","required":true,"description":"Exact lowercase sport. Leading and trailing spaces are ignored. A blank value is treated as missing.","schema":{"type":"string","enum":["ski","snowboard","mtb"]},"example":"snowboard"},{"name":"date","in":"query","required":false,"description":"One Europe/Paris calendar day, YYYY-MM-DD, from today through 365 days ahead. Required when from and to are absent. Do not send it with from or to.","schema":{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"example":"2026-12-27"},{"name":"from","in":"query","required":false,"description":"First day of an inclusive range, YYYY-MM-DD. Send it with to, and not with date. The range is at most 14 days and must start on or before to. Each day must be from today through 365 days ahead.","schema":{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"example":"2026-12-27"},{"name":"to","in":"query","required":false,"description":"Last day of an inclusive range, YYYY-MM-DD. Send it with from, and not with date.","schema":{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"example":"2026-12-27"},{"name":"resort","in":"query","required":false,"description":"Resort name, 1 to 80 characters, with no ASCII control characters. Matching ignores case, accents, and extra spaces. The response keeps the stored spelling. Omitted means every resort.","schema":{"type":"string","minLength":1,"maxLength":80},"example":"Morzine"},{"name":"duration","in":"query","required":false,"description":"Exact session length in minutes, a whole number from 1 to 1440. A blank or non-numeric value is rejected. Omitted means every duration.","schema":{"type":"integer","minimum":1,"maximum":1440},"example":120},{"name":"language","in":"query","required":false,"description":"Exact language name, 1 to 40 characters. It must start with a letter. The rest may be letters, spaces, apostrophes, or hyphens. Matching is case-insensitive. Omitted means every language.","schema":{"type":"string","minLength":1,"maxLength":40},"example":"English"},{"name":"instructor","in":"query","required":false,"description":"Public profile slug, 1 to 40 characters. It starts with a letter or number. The rest may be letters, numbers, or hyphens. Matching is case-insensitive. A slug of the right shape that is not a public instructor is HTTP 404. Omitted means every instructor.","schema":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[A-Za-z0-9][A-Za-z0-9-]{0,39}$"}},{"name":"party","in":"query","required":false,"description":"Riders in the group, a whole number from 1 to 99. Sessions whose instructor cannot take that many people are omitted. An instructor with no stored group size is treated as 4 for this comparison only. Omitted means no group-size filter.","schema":{"type":"integer","minimum":1,"maximum":99},"example":2}],"responses":{"200":{"description":"Live availability. offers is empty when nothing matched. That is not an error.","headers":{"Cache-Control":{"schema":{"type":"string","const":"no-store"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailabilityResult"},"examples":{"shape":{"summary":"Shape only. Example C. is not a Yeww instructor and this is not a live listing.","value":{"timezone":"Europe/Paris","checked_at":"2026-11-12T18:00:00.000Z","truncated":false,"offers":[{"coach_name":"Example C.","profile_url":"https://yeww.app/coaches/example","verified":true,"sports":["snowboard"],"resorts":["Morzine"],"languages":["English"],"session_name":"Afternoon","date":"2026-12-27","start_time":"13:10","end_time":"15:10","duration_minutes":120,"price":{"amount":"165.00","currency":"EUR","type":"customer"},"booking_url":"https://yeww.app/coaches/example/book?date=2026-12-27&start=13%3A10&duration=120"}]}},"empty":{"summary":"A valid query that found nobody free.","value":{"timezone":"Europe/Paris","checked_at":"2026-11-12T18:00:00.000Z","truncated":false,"offers":[]}}}}}},"400":{"description":"The query was rejected. The body is { \"error\": \"...\" } and includes no sessions. Missing required parameter: sport. Missing required parameter: date. Missing required parameter: from. Missing required parameter: to. Use either date or from and to, not both. Date must be YYYY-MM-DD. Date range must start on or before its end. Date range must be 14 days or fewer. Date must be from today through 365 days ahead. Sport must be ski, snowboard or mtb. Unknown parameter: followed by the parameter name. Invalid parameter: resort. Invalid parameter: duration. Duration must be a whole number of minutes from 1 to 1440. Invalid parameter: language. Invalid parameter: instructor. Invalid parameter: party. Party must be a whole number from 1 to 99.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"sport":{"value":{"error":"Missing required parameter: sport"}},"date":{"value":{"error":"Missing required parameter: date"}},"range":{"value":{"error":"Date range must be 14 days or fewer"}},"unknown":{"value":{"error":"Unknown parameter: price"}}}}}},"404":{"description":"Instructor not found when the instructor slug is well formed but is not a public instructor. Not found when this deployment has the public availability API switched off. https://yeww.app has it switched on.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"instructor":{"value":{"error":"Instructor not found"}},"disabled":{"value":{"error":"Not found"}}}}}},"429":{"description":"More than 30 requests per minute for this caller. Wait for Retry-After. The body includes no sessions.","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Seconds to wait."},"Cache-Control":{"schema":{"type":"string","const":"no-store"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Too many attempts. Please try again shortly."}}}},"500":{"description":"The check failed. The body includes no sessions and no database message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Could not check availability"}}}},"503":{"description":"The rate limiter could not run. This is not an invalid request and it includes no sessions.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Rate limiter unavailable"}}}}}}}},"components":{"schemas":{"Error":{"type":"object","additionalProperties":false,"required":["error"],"properties":{"error":{"type":"string"}}},"CustomerPrice":{"type":"object","additionalProperties":false,"required":["amount","currency","type"],"properties":{"amount":{"type":"string","description":"Euros with two decimal places.","example":"165.00"},"currency":{"type":"string","const":"EUR"},"type":{"type":"string","const":"customer","description":"The final amount the customer is charged."}}},"Offer":{"type":"object","additionalProperties":false,"required":["coach_name","profile_url","verified","sports","resorts","languages","session_name","date","start_time","end_time","duration_minutes","price","booking_url"],"properties":{"coach_name":{"type":"string","description":"Public shortened name. Not an internal id."},"profile_url":{"type":"string","format":"uri"},"verified":{"type":"boolean","const":true},"sports":{"type":"array","items":{"type":"string","enum":["ski","snowboard","mtb"]}},"resorts":{"type":"array","items":{"type":"string"},"description":"Resort names, not meeting points."},"languages":{"type":"array","items":{"type":"string"}},"session_name":{"type":"string"},"date":{"type":"string","format":"date"},"start_time":{"type":"string","pattern":"^\\d{2}:\\d{2}$","description":"Europe/Paris wall-clock time."},"end_time":{"type":"string","pattern":"^\\d{2}:\\d{2}$","description":"Europe/Paris wall-clock time."},"duration_minutes":{"type":"integer"},"price":{"$ref":"#/components/schemas/CustomerPrice"},"booking_url":{"type":"string","format":"uri","description":"Yeww booking page. It checks that this session is still free."}}},"AvailabilityResult":{"type":"object","additionalProperties":false,"required":["timezone","checked_at","truncated","offers"],"properties":{"timezone":{"type":"string","const":"Europe/Paris"},"checked_at":{"type":"string","format":"date-time","description":"UTC time when the query ran."},"truncated":{"type":"boolean"},"offers":{"type":"array","items":{"$ref":"#/components/schemas/Offer"}}}}}}}