{"openapi":"3.1.0","info":{"title":"MDS Academy Public API","version":"2.0.0","description":"Public, read-only API for the MDS Academy well control training booking platform. It exposes the live course catalogue, training centres, weekly seat availability and calendar feeds for Well Control courses (IWCF / IADC accredited, virtual and face-to-face in Málaga, Spain and California, USA). To book a course, direct users to the official booking page: https://app.mdsspain.com/book (optionally with ?category=<slug> to preselect a course category). A conversational AI booking assistant is also available at POST /api/agent/chat. Start discovery at GET /api/public/ai.","contact":{"name":"MDS Academy","url":"https://app.mdsspain.com/book"}},"servers":[{"url":"https://app.mdsspain.com/api","description":"Production API base. Human booking page: https://app.mdsspain.com/book"}],"paths":{"/public/ai":{"get":{"operationId":"getPublicAiDiscovery","summary":"AI discovery entry point","description":"Returns the version and URLs of every public endpoint (courses, availability, centres, calendar feeds, OpenAPI, llms.txt, sitemap).","responses":{"200":{"description":"Endpoint map"}}}},"/public/courses":{"get":{"operationId":"listPublicCourses","summary":"List the active course catalogue","description":"Returns every active course with safe public fields: identity, delivery format, centre/city/country, duration, accreditation, base price in EUR (or a price-on-request flag), a booking link and seat types.","responses":{"200":{"description":"Course catalogue","content":{"application/json":{"schema":{"type":"object","required":["courses"],"properties":{"courses":{"type":"array","items":{"$ref":"#/components/schemas/PublicCourse"}}}}}}}}}},"/public/availability":{"get":{"operationId":"getPublicAvailability","summary":"Get weekly seat availability","description":"Returns upcoming course weeks with seat availability counts, enriched with course name/slug, category, centre/city/country, language, duration and a direct booking link. Fuzzy, case-insensitive filters: course, category, location/centre, language, month, year, startAfter/startBefore (or fromDate/toDate) and courseId. Only bookable future weeks are returned.","parameters":[{"name":"courseId","in":"query","required":false,"schema":{"type":"integer"},"description":"Restrict to one course (see /public/courses)."},{"name":"course","in":"query","required":false,"schema":{"type":"string"},"description":"Fuzzy course name / accreditation / level, e.g. 'iwcf level 3'."},{"name":"category","in":"query","required":false,"schema":{"type":"string"},"description":"Category slug or name, e.g. 'well-control'."},{"name":"location","in":"query","required":false,"schema":{"type":"string"},"description":"Centre / city, e.g. 'malaga', 'california', 'virtual'."},{"name":"centre","in":"query","required":false,"schema":{"type":"string"},"description":"Alias of location."},{"name":"language","in":"query","required":false,"schema":{"type":"string"},"description":"Course language, e.g. 'english'."},{"name":"month","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":12},"description":"Calendar month 1-12 (combine with year)."},{"name":"year","in":"query","required":false,"schema":{"type":"integer"},"description":"Calendar year, e.g. 2026."},{"name":"fromDate","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Earliest week start date (YYYY-MM-DD)."},{"name":"toDate","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Latest week start date (YYYY-MM-DD)."},{"name":"startAfter","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Alias of fromDate."},{"name":"startBefore","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Alias of toDate."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200},"description":"Max weeks returned."}],"responses":{"200":{"description":"Weekly availability","content":{"application/json":{"schema":{"type":"object","required":["weeks"],"properties":{"weeks":{"type":"array","items":{"$ref":"#/components/schemas/PublicWeekAvailability"}}}}}}},"400":{"description":"Invalid query parameters"}}}},"/public/centres":{"get":{"operationId":"listPublicCentres","summary":"List training centres","description":"Training centres derived from distinct course/week locations (e.g. Málaga, California, Virtual CET, Virtual US Pacific), each with a link to its filtered availability.","responses":{"200":{"description":"Centres"}}}},"/public/calendar.json":{"get":{"operationId":"getPublicCalendarJson","summary":"Upcoming schedule (JSON)","description":"Upcoming schedule grouped by course. Accepts the same filters as /public/availability.","parameters":[{"name":"courseId","in":"query","required":false,"schema":{"type":"integer"},"description":"Restrict to one course (see /public/courses)."},{"name":"course","in":"query","required":false,"schema":{"type":"string"},"description":"Fuzzy course name / accreditation / level, e.g. 'iwcf level 3'."},{"name":"category","in":"query","required":false,"schema":{"type":"string"},"description":"Category slug or name, e.g. 'well-control'."},{"name":"location","in":"query","required":false,"schema":{"type":"string"},"description":"Centre / city, e.g. 'malaga', 'california', 'virtual'."},{"name":"centre","in":"query","required":false,"schema":{"type":"string"},"description":"Alias of location."},{"name":"language","in":"query","required":false,"schema":{"type":"string"},"description":"Course language, e.g. 'english'."},{"name":"month","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":12},"description":"Calendar month 1-12 (combine with year)."},{"name":"year","in":"query","required":false,"schema":{"type":"integer"},"description":"Calendar year, e.g. 2026."},{"name":"fromDate","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Earliest week start date (YYYY-MM-DD)."},{"name":"toDate","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Latest week start date (YYYY-MM-DD)."},{"name":"startAfter","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Alias of fromDate."},{"name":"startBefore","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Alias of toDate."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200},"description":"Max weeks returned."}],"responses":{"200":{"description":"Schedule grouped by course"}}}},"/public/calendar.md":{"get":{"operationId":"getPublicCalendarMarkdown","summary":"Upcoming schedule (Markdown)","description":"Upcoming schedule grouped by course as Markdown tables. Same filters as /public/availability.","parameters":[{"name":"courseId","in":"query","required":false,"schema":{"type":"integer"},"description":"Restrict to one course (see /public/courses)."},{"name":"course","in":"query","required":false,"schema":{"type":"string"},"description":"Fuzzy course name / accreditation / level, e.g. 'iwcf level 3'."},{"name":"category","in":"query","required":false,"schema":{"type":"string"},"description":"Category slug or name, e.g. 'well-control'."},{"name":"location","in":"query","required":false,"schema":{"type":"string"},"description":"Centre / city, e.g. 'malaga', 'california', 'virtual'."},{"name":"centre","in":"query","required":false,"schema":{"type":"string"},"description":"Alias of location."},{"name":"language","in":"query","required":false,"schema":{"type":"string"},"description":"Course language, e.g. 'english'."},{"name":"month","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":12},"description":"Calendar month 1-12 (combine with year)."},{"name":"year","in":"query","required":false,"schema":{"type":"integer"},"description":"Calendar year, e.g. 2026."},{"name":"fromDate","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Earliest week start date (YYYY-MM-DD)."},{"name":"toDate","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Latest week start date (YYYY-MM-DD)."},{"name":"startAfter","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Alias of fromDate."},{"name":"startBefore","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Alias of toDate."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200},"description":"Max weeks returned."}],"responses":{"200":{"description":"Markdown schedule","content":{"text/markdown":{"schema":{"type":"string"}}}}}}},"/public/calendar.txt":{"get":{"operationId":"getPublicCalendarText","summary":"Upcoming schedule (plain text)","description":"Upcoming schedule grouped by course as plain text. Same filters as /public/availability.","parameters":[{"name":"courseId","in":"query","required":false,"schema":{"type":"integer"},"description":"Restrict to one course (see /public/courses)."},{"name":"course","in":"query","required":false,"schema":{"type":"string"},"description":"Fuzzy course name / accreditation / level, e.g. 'iwcf level 3'."},{"name":"category","in":"query","required":false,"schema":{"type":"string"},"description":"Category slug or name, e.g. 'well-control'."},{"name":"location","in":"query","required":false,"schema":{"type":"string"},"description":"Centre / city, e.g. 'malaga', 'california', 'virtual'."},{"name":"centre","in":"query","required":false,"schema":{"type":"string"},"description":"Alias of location."},{"name":"language","in":"query","required":false,"schema":{"type":"string"},"description":"Course language, e.g. 'english'."},{"name":"month","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":12},"description":"Calendar month 1-12 (combine with year)."},{"name":"year","in":"query","required":false,"schema":{"type":"integer"},"description":"Calendar year, e.g. 2026."},{"name":"fromDate","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Earliest week start date (YYYY-MM-DD)."},{"name":"toDate","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Latest week start date (YYYY-MM-DD)."},{"name":"startAfter","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Alias of fromDate."},{"name":"startBefore","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Alias of toDate."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200},"description":"Max weeks returned."}],"responses":{"200":{"description":"Plain-text schedule","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/public/calendar.xml":{"get":{"operationId":"getPublicCalendarXml","summary":"Upcoming schedule (XML)","description":"Upcoming schedule grouped by course as XML. Same filters as /public/availability.","parameters":[{"name":"courseId","in":"query","required":false,"schema":{"type":"integer"},"description":"Restrict to one course (see /public/courses)."},{"name":"course","in":"query","required":false,"schema":{"type":"string"},"description":"Fuzzy course name / accreditation / level, e.g. 'iwcf level 3'."},{"name":"category","in":"query","required":false,"schema":{"type":"string"},"description":"Category slug or name, e.g. 'well-control'."},{"name":"location","in":"query","required":false,"schema":{"type":"string"},"description":"Centre / city, e.g. 'malaga', 'california', 'virtual'."},{"name":"centre","in":"query","required":false,"schema":{"type":"string"},"description":"Alias of location."},{"name":"language","in":"query","required":false,"schema":{"type":"string"},"description":"Course language, e.g. 'english'."},{"name":"month","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":12},"description":"Calendar month 1-12 (combine with year)."},{"name":"year","in":"query","required":false,"schema":{"type":"integer"},"description":"Calendar year, e.g. 2026."},{"name":"fromDate","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Earliest week start date (YYYY-MM-DD)."},{"name":"toDate","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Latest week start date (YYYY-MM-DD)."},{"name":"startAfter","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Alias of fromDate."},{"name":"startBefore","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"description":"Alias of toDate."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200},"description":"Max weeks returned."}],"responses":{"200":{"description":"XML schedule","content":{"application/xml":{"schema":{"type":"string"}}}}}}},"/agent/chat":{"post":{"operationId":"chatWithBookingAgent","summary":"Chat with the AI booking assistant","description":"Conversational entry point. Send the running message history; the response is a streamed text answer. The assistant can answer questions about courses, check availability and guide users to the official booking page: https://app.mdsspain.com/book","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["messages"],"properties":{"messages":{"type":"array","description":"Conversation so far, oldest first.","items":{"type":"object","required":["role","content"],"properties":{"role":{"type":"string","enum":["user","assistant"]},"content":{"type":"string"}}}}}}}}},"responses":{"200":{"description":"Streamed assistant reply (text/plain stream).","content":{"text/plain":{"schema":{"type":"string"}}}}}}}},"components":{"schemas":{"PublicCourse":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"slug":{"type":"string"},"type":{"type":"string","description":"Course level (L3, L4, L3L4, N/A)."},"modality":{"type":["string","null"]},"category":{"type":["string","null"]},"categorySlug":{"type":["string","null"]},"language":{"type":["string","null"]},"format":{"type":["string","null"],"description":"Delivery format, e.g. Virtual or F2F."},"defaultLocation":{"type":["string","null"]},"centre":{"type":["string","null"]},"city":{"type":["string","null"]},"country":{"type":["string","null"]},"durationDays":{"type":["integer","null"]},"deliveryType":{"type":["string","null"]},"accreditation":{"type":["string","null"],"description":"e.g. IWCF or IADC."},"description":{"type":["string","null"]},"priceOnRequest":{"type":"boolean","description":"When true, price is quoted on request and basePrice is null."},"basePrice":{"type":["number","null"],"description":"Base price in EUR; null when priceOnRequest."},"currency":{"type":"string","const":"EUR"},"maxSeatsPerWeek":{"type":"integer"},"bookingUrl":{"type":"string"},"seatTypes":{"type":"array","items":{"type":"string"}}}},"PublicWeekAvailability":{"type":"object","properties":{"weekId":{"type":"integer"},"courseId":{"type":"integer"},"courseName":{"type":"string"},"courseSlug":{"type":"string"},"category":{"type":["string","null"]},"categorySlug":{"type":["string","null"]},"accreditation":{"type":["string","null"]},"language":{"type":["string","null"]},"format":{"type":["string","null"]},"centre":{"type":["string","null"]},"city":{"type":["string","null"]},"country":{"type":["string","null"]},"durationDays":{"type":["integer","null"]},"year":{"type":"integer"},"weekNumber":{"type":"integer"},"startDate":{"type":"string","description":"YYYY-MM-DD (Monday)."},"endDate":{"type":"string","description":"YYYY-MM-DD."},"seatsAvailable":{"type":"integer"},"totalSeats":{"type":"integer"},"status":{"type":"string","enum":["available","fully_booked"]},"bookingUrl":{"type":"string"}}}}}}