{"openapi":"3.1.0","info":{"title":"marocain.investments — Public Listings API","version":"1.0.0","description":"Read-only access to AI-graded luxury property listings across Morocco. Used by the marocain.investments ChatGPT app for natural-language search.","contact":{"email":"ops@marocain.investments","url":"https://marocain.investments"}},"servers":[{"url":"https://marocain.investments","description":"Production"}],"paths":{"/api/public/listings/search":{"get":{"operationId":"searchListings","summary":"Search AI-graded luxury Moroccan property listings.","description":"Filter by city, district, typology, price range, room count, and minimum AI score thresholds. Returns up to 50 results sorted by Window-View score.","parameters":[{"name":"city","in":"query","schema":{"type":"string","enum":["Tangier","Casablanca","Marrakech","Rabat","Agadir","Essaouira","Tetouan","Fes"]}},{"name":"district","in":"query","schema":{"type":"string"}},{"name":"typology","in":"query","schema":{"type":"string","enum":["villa","penthouse","apartment","estate","townhouse"]}},{"name":"min_price_usd","in":"query","schema":{"type":"integer","minimum":0}},{"name":"max_price_usd","in":"query","schema":{"type":"integer","minimum":0}},{"name":"min_rooms","in":"query","schema":{"type":"integer","minimum":0}},{"name":"min_window_view","in":"query","schema":{"type":"integer","minimum":0,"maximum":100}},{"name":"min_wc2030","in":"query","schema":{"type":"integer","minimum":0,"maximum":100}},{"name":"q","in":"query","schema":{"type":"string"},"description":"Free-text substring search in listing title."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"responses":{"200":{"description":"Listings array","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"limit":{"type":"integer"},"items":{"type":"array","items":{"$ref":"#/components/schemas/ListingSummary"}}}}}}}}}},"/api/public/listings/{id}":{"get":{"operationId":"getListing","summary":"Get full detail for a single AI-graded listing.","description":"Returns the complete listing record including description, M-Value AVM, AI score explanation, and trust signals (title verified, FCR status).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Listing detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingDetail"}}}},"404":{"description":"Listing not found"}}}}},"components":{"schemas":{"AIScores":{"type":"object","properties":{"window_view":{"type":"integer","description":"0–100. Ocean/medina/skyline frontage from primary living spaces."},"structural":{"type":"integer","description":"0–100. Build quality, finishes, condition."},"wc2030":{"type":"integer","description":"0–100. Distance to World Cup 2030 host venues + TGV stations."},"methodology":{"type":"string","description":"e.g. 'vision-v1 (claude-sonnet-4-6)' or 'district-prior + coastal-proxy v1'."},"confidence":{"type":"number","minimum":0,"maximum":1,"nullable":true},"explanation":{"type":"string","nullable":true,"description":"AI-written rationale citing what the photos showed."}}},"Trust":{"type":"object","properties":{"title_verified":{"type":"boolean"},"title_verified_at":{"type":"string","format":"date-time","nullable":true},"fcr_status":{"type":"string","enum":["unknown","yes","setup_required","no"],"description":"Dirhams convertibles posture — see /legal/fcr."}}},"ListingSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"title":{"type":"string"},"city":{"type":"string"},"district":{"type":"string"},"typology":{"type":"string"},"price_usd":{"type":"integer"},"price_mad":{"type":"integer"},"rooms":{"type":"integer"},"bathrooms":{"type":"integer"},"surface_m2":{"type":"integer"},"base_yield_pct":{"type":"number"},"hero_image":{"type":"string","format":"uri","nullable":true},"ai_scores":{"$ref":"#/components/schemas/AIScores"},"trust":{"$ref":"#/components/schemas/Trust"},"status":{"type":"string"}}},"ListingDetail":{"allOf":[{"$ref":"#/components/schemas/ListingSummary"},{"type":"object","properties":{"description":{"type":"string","nullable":true},"lat":{"type":"number","nullable":true},"lng":{"type":"number","nullable":true},"images":{"type":"array","items":{"type":"string","format":"uri"}},"m_value":{"type":"object","nullable":true,"description":"Comparable-based AVM. Null when comp pool is too thin.","properties":{"m_value_usd":{"type":"integer"},"m_value_mad":{"type":"integer"},"confidence_low_usd":{"type":"integer"},"confidence_high_usd":{"type":"integer"},"comp_count":{"type":"integer"},"methodology":{"type":"string"},"per_m2_mad":{"type":"integer"}}},"source_url":{"type":"string","format":"uri","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}]}}}}