{"openapi":"3.1.0","info":{"title":"Mutuelle Horizon Démo — API métier fictive","version":"1.0.0","description":"Aucun contrat ni paiement. Web, REST et MCP appellent le même moteur. Prix EUR en centimes. Aucun champ source accepté : la route détermine la source."},"servers":[{"url":"https://demo-mutuelle.trainedpeople.com"}],"paths":{"/api/plans":{"get":{"operationId":"listPlans","summary":"Lire les trois formules fictives","responses":{"200":{"description":"Plans","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Plans"}}}}}}},"/api/quote/requirements":{"get":{"operationId":"quoteRequirements","summary":"Données nécessaires et règles de collecte","responses":{"200":{"description":"Requirements","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Requirements"}}}}}}},"/api/quote/calculate":{"post":{"operationId":"calculateQuote","summary":"Calculer et recommander sans créer de devis","parameters":[{"name":"X-Demo-Session","in":"header","schema":{"type":"string","format":"uuid"},"description":"Session pédagogique à réutiliser pour relier les événements."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteInput"}}}},"responses":{"200":{"description":"Calculation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Calculation"}}}},"400":{"description":"Requête JSON invalide ou clé d’idempotence invalide"},"422":{"description":"Validation stricte échouée"},"429":{"description":"Limite de requêtes atteinte"}}}},"/api/quotes":{"post":{"operationId":"createQuote","summary":"Créer un devis fictif persistant","parameters":[{"name":"X-Demo-Session","in":"header","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","schema":{"type":"string","format":"uuid"},"description":"Réutiliser la même session et clé pour un retry identique."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteRequest"}}}},"responses":{"201":{"description":"Quote","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}}},"400":{"description":"Requête JSON invalide ou clé d’idempotence invalide"},"409":{"description":"Clé réutilisée avec un payload différent"},"422":{"description":"Validation stricte échouée"},"429":{"description":"Limite de requêtes atteinte"}}}},"/api/quotes/{token}":{"get":{"operationId":"getQuote","summary":"Relire un devis via son token","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-f0-9]{64}$"},"description":"Token non prédictible, jamais le numéro MH."}],"responses":{"200":{"description":"Quote","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}}},"404":{"description":"Devis introuvable"}}}},"/health":{"get":{"operationId":"health","summary":"Santé application et SQLite","responses":{"200":{"description":"Application et base accessibles"}}}}},"components":{"schemas":{"QuoteInput":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"postal_code":{"type":"string","pattern":"^(?:0[1-9]|[1-8][0-9]|9[0-8])[0-9]{3}$"},"adult_ages":{"minItems":1,"maxItems":4,"type":"array","items":{"type":"integer","minimum":18,"maximum":100}},"child_count":{"type":"integer","minimum":0,"maximum":10},"requested_coverage":{"type":"string","enum":["essentiel","confort","premium","conseillez-moi"]},"priority":{"type":"string","enum":["equilibre","hospitalisation","dentaire","optique"]}},"required":["postal_code","adult_ages","child_count","requested_coverage","priority"],"additionalProperties":false},"QuoteRequest":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"input":{"type":"object","properties":{"postal_code":{"type":"string","pattern":"^(?:0[1-9]|[1-8][0-9]|9[0-8])[0-9]{3}$"},"adult_ages":{"minItems":1,"maxItems":4,"type":"array","items":{"type":"integer","minimum":18,"maximum":100}},"child_count":{"type":"integer","minimum":0,"maximum":10},"requested_coverage":{"type":"string","enum":["essentiel","confort","premium","conseillez-moi"]},"priority":{"type":"string","enum":["equilibre","hospitalisation","dentaire","optique"]}},"required":["postal_code","adult_ages","child_count","requested_coverage","priority"],"additionalProperties":false},"plan_id":{"type":"string","enum":["essentiel","confort","premium"]},"contact":{"type":"object","properties":{"first_name":{"type":"string","minLength":1,"maxLength":60},"email":{"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,}$"}},"additionalProperties":false}},"required":["input","plan_id"],"additionalProperties":false},"Plan":{"type":"object","required":["id","name","coefficient","guarantees"],"properties":{"id":{"enum":["essentiel","confort","premium"]},"name":{"type":"string"},"tagline":{"type":"string"},"description":{"type":"string"},"coefficient":{"type":"integer"},"guarantees":{"type":"array","items":{"type":"string"},"minItems":6,"maxItems":6}}},"Offer":{"type":"object","required":["plan","monthly_price_cents","currency"],"properties":{"plan":{"$ref":"#/components/schemas/Plan"},"monthly_price_cents":{"type":"integer","minimum":0},"currency":{"const":"EUR"}}},"Plans":{"type":"object","properties":{"plans":{"type":"array","items":{"$ref":"#/components/schemas/Plan"}},"fictional":{"const":true}}},"Requirements":{"type":"object","properties":{"required":{"type":"array","items":{"type":"string"}},"fields":{"type":"object"},"instructions":{"type":"string"},"contact_optional":{"type":"boolean"},"fictional":{"const":true}}},"Calculation":{"type":"object","required":["input","recommended","alternatives","explanation","fictional"],"properties":{"input":{"$ref":"#/components/schemas/QuoteInput"},"recommended":{"$ref":"#/components/schemas/Offer"},"alternatives":{"type":"array","items":{"$ref":"#/components/schemas/Offer"}},"explanation":{"type":"string"},"breakdown":{"type":"object"},"fictional":{"const":true}}},"Quote":{"type":"object","required":["token","number","url","offer","input","valid_until","source"],"properties":{"token":{"type":"string","pattern":"^[a-f0-9]{64}$"},"number":{"type":"string"},"url":{"type":"string","format":"uri"},"created_at":{"type":"string","format":"date-time"},"valid_until":{"type":"string","format":"date-time"},"input":{"$ref":"#/components/schemas/QuoteInput"},"offer":{"$ref":"#/components/schemas/Offer"},"source":{"enum":["web","rest","mcp","ucp"]},"status":{"enum":["demo","expired"]},"fictional":{"const":true},"disclaimer":{"type":"string"}}}}}}