{
 "openapi": "3.1.0",
 "info": {
  "title": "FindADoctor.si France API",
  "version": "fr-2026-10-16.1",
  "description": "Read-only JSON API with the same tools as the MCP server. No sign-up needed. Not medical advice; in an emergency call 15 (SAMU) or 112. Responses list the main fields (components.schemas); other fields may appear, so ignore fields you do not know. Fields without data are left out. Doctor details include Transparence Sant\u00e9 data (licence CC BY-NC-SA 4.0): keep the source and licence when you reuse them. Responses are not for search-engine indexing (X-Robots-Tag: noindex).",
  "x-llms-txt": "https://api-fr.findadoctor.si/llms.txt"
 },
 "servers": [
  {
   "url": "https://api-fr.findadoctor.si"
  }
 ],
 "components": {
  "schemas": {
   "Provider": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string"
     },
     "url": {
      "type": "string"
     },
     "data_version": {
      "type": "string"
     }
    },
    "description": "who publishes this data and which build"
   },
   "Error": {
    "type": "object",
    "properties": {
     "error": {
      "type": "string",
      "description": "bad_args, too_slow, daily_limit, rate_limited, busy, unavailable, sign_in_required, invalid_token, cross_site, not_found, internal"
     },
     "message": {
      "type": "string",
      "description": "what to change or when to retry"
     }
    }
   },
   "SearchItem": {
    "type": "object",
    "properties": {
     "doctor_id": {
      "type": "string",
      "pattern": "^fr_[0-9a-z]{12}$",
      "description": "use with get_doctor"
     },
     "name": {
      "type": "string"
     },
     "gender": {
      "type": "string",
      "enum": [
       "female",
       "male"
      ]
     },
     "specialties": {
      "type": "array",
      "items": {
       "type": "string",
       "description": "French, as registered (RPPS, Ameli) or on the profile page"
      }
     },
     "specialties_en": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "places": {
      "type": "array",
      "items": {
       "type": "string",
       "description": "practice: name, address, postcode and city (up to 3; the ones matching place first)"
      }
     },
     "fee_sectors": {
      "type": "array",
      "items": {
       "type": "string",
       "description": "Ameli fee category of the doctor's practices: Secteur 1 (standard fees), Secteur 2 (may charge extra), Non conventionn\u00e9"
      }
     },
     "optam": {
      "type": "boolean",
      "description": "signed up to OPTAM at some practice (agreed to limit extra fees)"
     },
     "match_basis": {
      "type": "string",
      "enum": [
       "stated_expertise",
       "official_competence",
       "hospital_department_or_training",
       "several_fields",
       "specialty",
       "specialty_usually_treats",
       "partial"
      ],
      "description": "with a need: where the doctor's own data matches it"
     },
     "register": {
      "type": "string",
      "enum": [
       "rpps",
       "ameli_only",
       "website_only"
      ],
      "description": "rpps = in the official register; ameli_only = only in the Assurance Maladie directory; website_only = not matched to the official registers"
     },
     "warnings": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "detail_has": {
      "type": "array",
      "items": {
       "type": "string",
       "description": "what get_doctor adds for this doctor"
      }
     }
    }
   },
   "SearchResult": {
    "type": "object",
    "properties": {
     "before_you_answer": {
      "type": "string"
     },
     "provider": {
      "$ref": "#/components/schemas/Provider"
     },
     "count": {
      "type": "integer"
     },
     "more": {
      "type": "boolean",
      "description": "more results after this page (paging stops at 30)"
     },
     "offset": {
      "type": "integer"
     },
     "doctors": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/SearchItem"
      }
     },
     "need_note": {
      "type": "string",
      "description": "with a need: no doctor lists all its words, or which specialties were added as specialty_usually_treats"
     },
     "specialty_from_need": {
      "type": "string",
      "description": "need was only a specialty name, so it was searched as specialty"
     },
     "place_from_need": {
      "type": "string",
      "description": "a city in need was read as the place"
     },
     "place_note": {
      "type": "string",
      "description": "how the place was read (city in several d\u00e9partements, or a practice name)"
     },
     "filter_note": {
      "type": "string",
      "description": "language, online booking and video filters only know doctors with a profile page"
     },
     "hospital": {
      "type": "object",
      "description": "with hospital_finess: the hospital site (or the sites of a legal entity)"
     },
     "hospital_warning": {
      "type": "string"
     },
     "hospital_note": {
      "type": "string"
     },
     "next_step": {
      "type": "string"
     }
    }
   },
   "Practice": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string"
     },
     "address": {
      "type": "string"
     },
     "postcode": {
      "type": "string"
     },
     "city": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     },
     "setting": {
      "type": "string",
      "description": "e.g. cabinet (office), \u00e9tablissement (hospital or clinic)"
     },
     "role": {
      "type": "string"
     },
     "sector": {
      "type": "string",
      "description": "Ameli fee category at this practice"
     },
     "optam": {
      "type": "string"
     },
     "finess": {
      "type": "string",
      "description": "hospital site FINESS number, when the practice is a hospital"
     },
     "source": {
      "type": "string",
      "description": "rpps, ameli or the profile page"
     }
    }
   },
   "IndustryLinks": {
    "type": "object",
    "properties": {
     "source": {
      "type": "string"
     },
     "years_covered": {
      "type": "string"
     },
     "declarations_matched": {
      "type": "integer"
     },
     "matched_by_name_only": {
      "type": "integer",
      "description": "declarations without an RPPS number, matched by name and place (see name_match_note)"
     },
     "name_match_note": {
      "type": "string"
     },
     "by_kind": {
      "type": "object",
      "properties": {
       "convention": {
        "type": "object",
        "properties": {
         "declarations": {
          "type": "integer"
         },
         "eur": {
          "type": "integer",
          "description": "sum of the declared amounts, euros"
         },
         "without_amount": {
          "type": "integer",
          "description": "declarations with no amount (agreements often have none)"
         }
        }
       },
       "avantage": {
        "type": "object",
        "properties": {
         "declarations": {
          "type": "integer"
         },
         "eur": {
          "type": "integer",
          "description": "sum of the declared amounts, euros"
         },
         "without_amount": {
          "type": "integer",
          "description": "declarations with no amount (agreements often have none)"
         }
        }
       },
       "remuneration": {
        "type": "object",
        "properties": {
         "declarations": {
          "type": "integer"
         },
         "eur": {
          "type": "integer",
          "description": "sum of the declared amounts, euros"
         },
         "without_amount": {
          "type": "integer",
          "description": "declarations with no amount (agreements often have none)"
         }
        }
       }
      },
      "description": "convention = agreement (e.g. a study, a congress invitation); avantage = benefit in kind or cash (meals, travel); remuneration = payment for work. Kept apart, never added together."
     },
     "recent_years": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "year": {
         "type": "integer"
        },
        "convention": {
         "type": "object",
         "properties": {
          "declarations": {
           "type": "integer"
          },
          "eur": {
           "type": "integer",
           "description": "sum of the declared amounts, euros"
          },
          "without_amount": {
           "type": "integer",
           "description": "declarations with no amount (agreements often have none)"
          }
         }
        },
        "avantage": {
         "type": "object",
         "properties": {
          "declarations": {
           "type": "integer"
          },
          "eur": {
           "type": "integer",
           "description": "sum of the declared amounts, euros"
          },
          "without_amount": {
           "type": "integer",
           "description": "declarations with no amount (agreements often have none)"
          }
         }
        },
        "remuneration": {
         "type": "object",
         "properties": {
          "declarations": {
           "type": "integer"
          },
          "eur": {
           "type": "integer",
           "description": "sum of the declared amounts, euros"
          },
          "without_amount": {
           "type": "integer",
           "description": "declarations with no amount (agreements often have none)"
          }
         }
        }
       }
      }
     },
     "recent_years_range": {
      "type": "string"
     },
     "top_companies": {
      "type": "object",
      "properties": {
       "convention": {
        "type": "array",
        "items": {
         "type": "object",
         "properties": {
          "company": {
           "type": "string"
          },
          "declarations": {
           "type": "integer"
          },
          "eur": {
           "type": "integer"
          },
          "years": {
           "type": "string"
          }
         }
        }
       },
       "avantage": {
        "type": "array",
        "items": {
         "type": "object",
         "properties": {
          "company": {
           "type": "string"
          },
          "declarations": {
           "type": "integer"
          },
          "eur": {
           "type": "integer"
          },
          "years": {
           "type": "string"
          }
         }
        }
       },
       "remuneration": {
        "type": "array",
        "items": {
         "type": "object",
         "properties": {
          "company": {
           "type": "string"
          },
          "declarations": {
           "type": "integer"
          },
          "eur": {
           "type": "integer"
          },
          "years": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "top_purposes": {
      "type": "object",
      "properties": {
       "convention": {
        "type": "array",
        "items": {
         "type": "object",
         "properties": {
          "purpose": {
           "type": "string"
          },
          "declarations": {
           "type": "integer"
          },
          "eur": {
           "type": "integer"
          }
         }
        }
       },
       "avantage": {
        "type": "array",
        "items": {
         "type": "object",
         "properties": {
          "purpose": {
           "type": "string"
          },
          "declarations": {
           "type": "integer"
          },
          "eur": {
           "type": "integer"
          }
         }
        }
       },
       "remuneration": {
        "type": "array",
        "items": {
         "type": "object",
         "properties": {
          "purpose": {
           "type": "string"
          },
          "declarations": {
           "type": "integer"
          },
          "eur": {
           "type": "integer"
          }
         }
        }
       }
      }
     },
     "check_on": {
      "type": "string",
      "description": "the official Transparence Sant\u00e9 site, to see each declaration"
     },
     "note": {
      "type": "string"
     }
    },
    "description": "Transparence Sant\u00e9 declarations by companies about this doctor, shown as declared (licence CC BY-NC-SA 4.0). Not evidence of expertise or wrongdoing; never used for ranking or filtering."
   },
   "Doctor": {
    "type": "object",
    "properties": {
     "before_you_answer": {
      "type": "string",
      "description": "read first: how to answer from this evidence (single doctor asked)"
     },
     "provider": {
      "$ref": "#/components/schemas/Provider"
     },
     "doctor_id": {
      "type": "string",
      "pattern": "^fr_[0-9a-z]{12}$",
      "description": "use with get_doctor"
     },
     "name": {
      "type": "string"
     },
     "gender": {
      "type": "string"
     },
     "rpps": {
      "type": "string",
      "description": "RPPS number (check on annuaire.sante.fr)"
     },
     "register": {
      "type": "string"
     },
     "register_check": {
      "type": "string"
     },
     "specialties_official": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "specialties_en": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "specialties_on_profile": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "official_competences": {
      "type": "array",
      "items": {
       "type": "string",
       "description": "extra competences recognised by the Ordre des m\u00e9decins"
      }
     },
     "university_diplomas": {
      "type": "array",
      "items": {
       "type": "string",
       "description": "DU / DIU recorded in RPPS"
      }
     },
     "practice_modes": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "practices": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Practice"
      }
     },
     "phones": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "fee_sectors": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "optam": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "carte_vitale": {
      "type": "boolean"
     },
     "third_party_payer": {
      "type": "boolean"
     },
     "stated_expertise": {
      "type": "array",
      "items": {
       "type": "string",
       "description": "from the doctor's Maiia or hospital page"
      }
     },
     "procedures_offered": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "hospital_departments": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "hospital_roles": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "qualifications": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "languages": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "consultation_fees": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "label": {
         "type": "string"
        },
        "price": {
         "type": "string"
        }
       }
      }
     },
     "online_booking": {
      "type": "boolean"
     },
     "teleconsultation": {
      "type": "boolean"
     },
     "booking_open_to_new_patients": {
      "type": "boolean",
      "description": "as shown on the profile page when read"
     },
     "industry_links": {
      "$ref": "#/components/schemas/IndustryLinks"
     },
     "sources": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "site": {
         "type": "string"
        },
        "url": {
         "type": "string"
        },
        "read_at_utc": {
         "type": "string"
        },
        "matched_by": {
         "type": "string"
        }
       }
      }
     }
    }
   },
   "DoctorBatch": {
    "type": "object",
    "properties": {
     "before_you_answer": {
      "type": "string",
      "description": "read first: how to answer from this evidence"
     },
     "provider": {
      "$ref": "#/components/schemas/Provider"
     },
     "daily_doctor_limit": {
      "type": "object",
      "description": "present when the daily limit matters: used, limit, message"
     },
     "doctors": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Doctor"
      }
     },
     "not_returned_yet": {
      "type": "object",
      "properties": {
       "message": {
        "type": "string"
       },
       "doctors": {
        "type": "array",
        "items": {
         "type": "object",
         "properties": {
          "doctor_id": {
           "type": "string",
           "pattern": "^fr_[0-9a-z]{12}$",
           "description": "use with get_doctor"
          }
         }
        }
       }
      },
      "description": "already counted; ask again for these at no extra cost"
     },
     "left_out": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "doctor_id": {
         "type": "string",
         "pattern": "^fr_[0-9a-z]{12}$",
         "description": "use with get_doctor"
        },
        "reason": {
         "type": "string"
        }
       }
      },
      "description": "not opened: daily limit reached"
     },
     "not_found": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "explain": {
      "type": "object",
      "description": "what some fields mean (once per reply)"
     },
     "licences": {
      "type": "object",
      "properties": {
       "transparence_sante": {
        "type": "string"
       }
      }
     },
     "note": {
      "type": "string"
     }
    }
   },
   "HospitalVolume": {
    "type": "object",
    "properties": {
     "finess": {
      "type": "string",
      "description": "hospital site FINESS number (use with search_doctors hospital_finess)"
     },
     "name": {
      "type": "string"
     },
     "postcode": {
      "type": "string"
     },
     "city": {
      "type": "string"
     },
     "departement": {
      "type": "string"
     },
     "acts": {
      "type": "integer",
      "description": "acts counted for the year asked"
     },
     "stays": {
      "type": "integer"
     },
     "same_day_share": {
      "type": "number"
     },
     "avg_nights": {
      "type": "number"
     },
     "acts_by_code": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "code": {
         "type": "string"
        },
        "acts": {
         "type": "integer"
        }
       }
      }
     },
     "acts_by_year": {
      "type": "object",
      "description": "acts per year, 2021-2025"
     },
     "doctors_with_register_address_here": {
      "type": "integer"
     }
    }
   },
   "HospitalVolumes": {
    "type": "object",
    "properties": {
     "before_you_answer": {
      "type": "string",
      "description": "read first: translate the French act labels; counts are per site, not per surgeon"
     },
     "provider": {
      "$ref": "#/components/schemas/Provider"
     },
     "year": {
      "type": "integer"
     },
     "count": {
      "type": "integer"
     },
     "more": {
      "type": "boolean"
     },
     "offset": {
      "type": "integer"
     },
     "acts_counted": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "code": {
         "type": "string"
        },
        "label": {
         "type": "string"
        },
        "france_acts_this_year": {
         "type": "integer"
        }
       }
      },
      "description": "the CCAM acts added up: check they fit the need"
     },
     "acts_note": {
      "type": "string"
     },
     "france_total": {
      "type": "object",
      "properties": {
       "acts": {
        "type": "integer"
       },
       "hospital_sites": {
        "type": "integer"
       },
       "note": {
        "type": "string"
       }
      }
     },
     "area_hospital_sites": {
      "type": "integer"
     },
     "hospitals": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/HospitalVolume"
      }
     },
     "place_note": {
      "type": "string"
     },
     "next_step": {
      "type": "string"
     },
     "note": {
      "type": "string"
     }
    }
   }
  },
  "securitySchemes": {
   "accountKey": {
    "type": "http",
    "scheme": "bearer",
    "description": "Optional account key (dk_...); accounts are by invitation during the trial."
   }
  }
 },
 "security": [
  {},
  {
   "accountKey": []
  }
 ],
 "paths": {
  "/api/v1/search": {
   "get": {
    "operationId": "searchDoctors",
    "summary": "Free short list of doctors in France for a need",
    "description": "Free short list of doctors in France for a need; use it first whenever the person needs a doctor, specialist or GP in France. Give at least one of need, specialty, place, name or hospital_finess. need = condition, procedure or focus, in French or English (e.g. 'endom\u00e9triose', 'proth\u00e8se genou', 'knee replacement', 'cataract'; common English words are also searched in French); matched against the expertise and procedures doctors state, their official competences and university diplomas, hospital departments and roles, and specialty. specialty = French or English (e.g. 'cardiologie', 'dermatology', 'p\u00e9diatre', 'ORL', 'GP', 'g\u00e9n\u00e9raliste'). place = city ('Lyon', 'Paris' includes all arrondissements), postcode ('75015'), arrondissement ('Paris 15', 'Lyon 3e'), d\u00e9partement number ('69', '2A') or a practice or hospital name; a text match on practice addresses, not a distance search. Each result: doctor_id, name, gender, specialties (French, as registered), specialties_en, places (up to 3 practices, the ones matching place first), fee_sectors (Ameli category: Secteur 1 = standard fees; Secteur 2 = may charge extra; Non conventionn\u00e9 = not contracted, little reimbursed), optam (agreed to limit extra fees), match_basis (with a need: stated_expertise, official_competence, hospital_department_or_training, several_fields, specialty, specialty_usually_treats, partial), register (rpps, ameli_only = only in the Assurance Maladie directory, website_only = not matched to the official registers), warnings (e.g. barred from practising) and detail_has (what get_doctor adds). With a need, results are ranked by how directly the doctor's own data matches it: all its words in the expertise or procedures the doctor states, then in official competences or university diplomas, then in hospital department, role or training, then spread over several fields, then in the specialty name; then, when the need is a condition few doctors list, doctors in the specialty that usually treats it (specialty_usually_treats); then doctors matching only some of the words. Without a need, doctors with more data (stated expertise, official competences, profile pages) come first, then in a fixed shuffled order. Not ranked by quality, outcomes, fees or industry links. Then call get_doctor with the doctor_ids you are considering. Up to 10 results per search and paging stops at 30: narrow the need or the place instead of paging.",
    "parameters": [
     {
      "name": "need",
      "in": "query",
      "required": false,
      "description": "Condition, procedure or focus, in French or English.",
      "schema": {
       "type": "string",
       "maxLength": 200
      }
     },
     {
      "name": "specialty",
      "in": "query",
      "required": false,
      "description": "Specialty in French or English, e.g. 'cardiologie', 'dermatology', 'ORL', 'GP' (see list_specialties).",
      "schema": {
       "type": "string",
       "maxLength": 200
      }
     },
     {
      "name": "place",
      "in": "query",
      "required": false,
      "description": "City, postcode, arrondissement ('Paris 15'), d\u00e9partement number ('69', '2A') or a practice or hospital name.",
      "schema": {
       "type": "string",
       "maxLength": 200
      }
     },
     {
      "name": "name",
      "in": "query",
      "required": false,
      "description": "Doctor's name or part of it, to check a named doctor.",
      "schema": {
       "type": "string",
       "maxLength": 200
      }
     },
     {
      "name": "gender",
      "in": "query",
      "required": false,
      "description": "Only when the person asks. From the register's civil title (Madame/Monsieur); recorded for almost all doctors.",
      "schema": {
       "type": "string",
       "enum": [
        "female",
        "male"
       ]
      }
     },
     {
      "name": "language",
      "in": "query",
      "required": false,
      "description": "Language other than French, e.g. 'English', 'Arabic', 'anglais'. Only known for doctors with a Maiia or hospital profile (about 1,800 list one); many others speak it too.",
      "schema": {
       "type": "string",
       "maxLength": 200
      }
     },
     {
      "name": "fee_sector",
      "in": "query",
      "required": false,
      "description": "Assurance Maladie fee category. secteur_1 = standard fees, no extra charges; secteur_1_or_optam = standard fees or agreed limits on extra fees; secteur_2 = may charge extra. Kept if ANY of the doctor's practices has it (it can differ by practice): check each practice in get_doctor. Most hospital-only doctors have no category. Default any.",
      "schema": {
       "type": "string",
       "enum": [
        "any",
        "secteur_1",
        "secteur_1_or_optam",
        "secteur_2"
       ]
      }
     },
     {
      "name": "online_booking",
      "in": "query",
      "required": false,
      "description": "True keeps doctors whose Maiia or hospital page shows online booking (Doctolib is not covered).",
      "schema": {
       "type": "boolean"
      }
     },
     {
      "name": "teleconsultation",
      "in": "query",
      "required": false,
      "description": "True keeps doctors offering video consultations on Maiia.",
      "schema": {
       "type": "boolean"
      }
     },
     {
      "name": "hospital_finess",
      "in": "query",
      "required": false,
      "description": "Keep doctors whose register address is this hospital site (FINESS number from hospital_procedure_volumes): mostly salaried hospital doctors.",
      "schema": {
       "type": "string",
       "maxLength": 200
      }
     },
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "description": "Default 10.",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 10
      }
     },
     {
      "name": "offset",
      "in": "query",
      "required": false,
      "description": "For paging (at most 20, so 30 results in all: narrow the search instead).",
      "schema": {
       "type": "integer",
       "minimum": 0,
       "maximum": 20
      }
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result (same as the MCP tool's result)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SearchResult"
        },
        "example": {
         "before_you_answer": "Reply in the language of the user's own message (if they wrote in English, answer in English), not in French just because the data is French: translate it. This is the free short list: who the doctors are, not the evidence. ...",
         "provider": {
          "name": "FindADoctor.si France",
          "url": "https://findadoctor.si/fr/",
          "data_version": "fr-public-2026-10-16.3"
         },
         "count": 1,
         "more": false,
         "offset": 0,
         "doctors": [
          {
           "doctor_id": "fr_4k9m2x7qph3t",
           "name": "Dr Exemple Chirurgien",
           "gender": "male",
           "specialties": [
            "Chirurgie orthop\u00e9dique et traumatologie"
           ],
           "specialties_en": [
            "Orthopaedic surgery"
           ],
           "places": [
            "Cabinet Exemple, 1 rue de l'Exemple, 69000 Lyon"
           ],
           "fee_sectors": [
            "Secteur 2"
           ],
           "optam": true,
           "match_basis": "stated_expertise",
           "register": "rpps",
           "detail_has": [
            "stated expertise",
            "official register entry",
            "fee category per practice"
           ]
          }
         ]
        }
       }
      }
     },
     "400": {
      "description": "bad arguments, or the search was too broad (too_slow): the message says what to change",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "the Authorization header was sent but is invalid or expired (invalid_token): send no header or a valid account key",
      "headers": {
       "WWW-Authenticate": {
        "schema": {
         "type": "string"
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "rate_limited (too many requests) or daily_limit (daily doctor limit reached); the message says when it resets",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "headers": {
       "Retry-After": {
        "description": "seconds to wait",
        "schema": {
         "type": "integer"
        }
       }
      }
     },
     "500": {
      "description": "internal error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "busy or starting (busy, unavailable): retry after Retry-After",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "headers": {
       "Retry-After": {
        "description": "seconds to wait",
        "schema": {
         "type": "integer"
        }
       }
      }
     }
    }
   }
  },
  "/api/v1/doctors/{doctor_id}": {
   "get": {
    "operationId": "getDoctor",
    "summary": "Evidence for one doctor (counted)",
    "description": "doctor_id from a search result. Each different doctor opened counts toward a daily limit (UTC day): 5 a day per network address without an account; opening a doctor again the same day is free.",
    "parameters": [
     {
      "name": "doctor_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "pattern": "^fr_[0-9a-z]{12}$"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result (same as the MCP tool's result)",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "provider": {
           "$ref": "#/components/schemas/Provider"
          }
         },
         "description": "Provider, then the Doctor fields, explain, licences and note"
        },
        "example": {
         "provider": {
          "name": "FindADoctor.si France",
          "url": "https://findadoctor.si/fr/",
          "data_version": "fr-public-2026-10-16.3"
         },
         "doctor_id": "fr_4k9m2x7qph3t",
         "name": "Dr Exemple Chirurgien",
         "rpps": "10000000000",
         "specialties_official": [
          "Chirurgie orthop\u00e9dique et traumatologie"
         ],
         "stated_expertise": [
          "Proth\u00e8se de genou",
          "Chirurgie du sport"
         ],
         "practices": [
          {
           "name": "Cabinet Exemple",
           "address": "1 rue de l'Exemple",
           "postcode": "69000",
           "city": "Lyon",
           "phone": "04 00 00 00 00",
           "sector": "Secteur 2",
           "optam": "OPTAM",
           "source": "ameli"
          }
         ],
         "sources": [
          {
           "site": "maiia",
           "url": "https://www.maiia.com/",
           "read_at_utc": "2026-10-13T14:00:00Z"
          }
         ]
        }
       }
      }
     },
     "400": {
      "description": "bad arguments, or the search was too broad (too_slow): the message says what to change",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "the Authorization header was sent but is invalid or expired (invalid_token): send no header or a valid account key",
      "headers": {
       "WWW-Authenticate": {
        "schema": {
         "type": "string"
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "rate_limited (too many requests) or daily_limit (daily doctor limit reached); the message says when it resets",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "headers": {
       "Retry-After": {
        "description": "seconds to wait",
        "schema": {
         "type": "integer"
        }
       }
      }
     },
     "500": {
      "description": "internal error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "busy or starting (busy, unavailable): retry after Retry-After",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "headers": {
       "Retry-After": {
        "description": "seconds to wait",
        "schema": {
         "type": "integer"
        }
       }
      }
     },
     "403": {
      "description": "cross_site: a web page in another site's browser asked for doctor details without an account key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "unknown doctor_id",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "found": {
           "type": "boolean",
           "enum": [
            false
           ]
          }
         }
        },
        "example": {
         "found": false
        }
       }
      }
     }
    }
   }
  },
  "/api/v1/doctors": {
   "get": {
    "operationId": "getDoctors",
    "summary": "Evidence for up to 10 doctors (counted)",
    "description": "ids = comma-separated doctor_ids from search results, up to 10. Each different doctor opened counts toward a daily limit (UTC day): 5 a day per network address without an account; opening a doctor again the same day is free. When the limit runs out mid-request, the doctors that fit are returned and the rest are listed in left_out. Doctors that do not fit in one reply are listed in not_returned_yet, already counted, so ask again for them at no extra cost. Web pages calling this from a browser need an account key.",
    "parameters": [
     {
      "name": "ids",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "e.g. fr_4k9m2x7qph3t,fr_8w2c5n1kd7ra"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result (same as the MCP tool's result)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/DoctorBatch"
        },
        "example": {
         "provider": {
          "name": "FindADoctor.si France",
          "url": "https://findadoctor.si/fr/",
          "data_version": "fr-public-2026-10-16.3"
         },
         "doctors": [
          {
           "doctor_id": "fr_4k9m2x7qph3t",
           "name": "Dr Exemple Chirurgien",
           "rpps": "10000000000",
           "specialties_official": [
            "Chirurgie orthop\u00e9dique et traumatologie"
           ],
           "stated_expertise": [
            "Proth\u00e8se de genou",
            "Chirurgie du sport"
           ],
           "practices": [
            {
             "name": "Cabinet Exemple",
             "address": "1 rue de l'Exemple",
             "postcode": "69000",
             "city": "Lyon",
             "phone": "04 00 00 00 00",
             "sector": "Secteur 2",
             "optam": "OPTAM",
             "source": "ameli"
            }
           ],
           "sources": [
            {
             "site": "maiia",
             "url": "https://www.maiia.com/",
             "read_at_utc": "2026-10-13T14:00:00Z"
            }
           ]
          }
         ]
        }
       }
      }
     },
     "400": {
      "description": "bad arguments, or the search was too broad (too_slow): the message says what to change",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "the Authorization header was sent but is invalid or expired (invalid_token): send no header or a valid account key",
      "headers": {
       "WWW-Authenticate": {
        "schema": {
         "type": "string"
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "rate_limited (too many requests) or daily_limit (daily doctor limit reached); the message says when it resets",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "headers": {
       "Retry-After": {
        "description": "seconds to wait",
        "schema": {
         "type": "integer"
        }
       }
      }
     },
     "500": {
      "description": "internal error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "busy or starting (busy, unavailable): retry after Retry-After",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "headers": {
       "Retry-After": {
        "description": "seconds to wait",
        "schema": {
         "type": "integer"
        }
       }
      }
     },
     "403": {
      "description": "cross_site: a web page in another site's browser asked for doctor details without an account key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "unknown doctor_id",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "found": {
           "type": "boolean",
           "enum": [
            false
           ]
          }
         }
        },
        "example": {
         "found": false
        }
       }
      }
     }
    }
   }
  },
  "/api/v1/procedure-volumes": {
   "get": {
    "operationId": "hospitalProcedureVolumes",
    "summary": "Which French hospitals and clinics perform a procedure most (Open CCAM)",
    "description": "Which French hospitals and private clinics perform a procedure most, from Open CCAM (ATIH): number of acts per hospital site per year, 2021-2025, public and private. Counts hospital stays and day cases only (PMSI MCO); procedures done in a doctor's office or a hospital outpatient clinic are not counted, and a site with fewer than 11 stays for an act is not listed. procedure = English or French text ('cataract', 'knee replacement', 'proth\u00e8se genou', 'coloscopie', 'ablation fibrillation auriculaire') or CCAM codes; the reply lists the CCAM acts it added up, so check they fit the need (add-on codes and pathology are left out of text matches). For 'aneurysm' or 'stent' say where (brain, aorta, heart, carotid). place = city, postcode, Paris/Lyon/Marseille arrondissement, d\u00e9partement number or a hospital FINESS number; without place it ranks all of France. Hospital-level only: it does not say which surgeon operates. Then use search_doctors with hospital_finess (salaried hospital doctors) or with the hospital's postcode and the specialty (self-employed surgeons at private clinics). Free. On this web API pass the procedure as text or CCAM codes in procedure (the codes list is MCP only).",
    "parameters": [
     {
      "name": "procedure",
      "in": "query",
      "required": false,
      "description": "Procedure in English or French, or CCAM codes (e.g. 'BFGA427'; an 8th phase digit is dropped).",
      "schema": {
       "type": "string",
       "maxLength": 200
      }
     },
     {
      "name": "place",
      "in": "query",
      "required": false,
      "description": "City, postcode, arrondissement ('Paris 15'), d\u00e9partement number (2A, 2B, 971-976), or hospital FINESS number.",
      "schema": {
       "type": "string",
       "maxLength": 200
      }
     },
     {
      "name": "year",
      "in": "query",
      "required": false,
      "description": "Default latest (2025).",
      "schema": {
       "type": "integer",
       "minimum": 2021,
       "maximum": 2025
      }
     },
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "description": "Default 10.",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 20
      }
     },
     {
      "name": "offset",
      "in": "query",
      "required": false,
      "description": "For paging (at most 100).",
      "schema": {
       "type": "integer",
       "minimum": 0,
       "maximum": 100
      }
     }
    ],
    "responses": {
     "200": {
      "description": "JSON result (same as the MCP tool's result)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/HospitalVolumes"
        }
       }
      }
     },
     "400": {
      "description": "bad arguments, or the search was too broad (too_slow): the message says what to change",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "the Authorization header was sent but is invalid or expired (invalid_token): send no header or a valid account key",
      "headers": {
       "WWW-Authenticate": {
        "schema": {
         "type": "string"
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "rate_limited (too many requests) or daily_limit (daily doctor limit reached); the message says when it resets",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "headers": {
       "Retry-After": {
        "description": "seconds to wait",
        "schema": {
         "type": "integer"
        }
       }
      }
     },
     "500": {
      "description": "internal error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "busy or starting (busy, unavailable): retry after Retry-After",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "headers": {
       "Retry-After": {
        "description": "seconds to wait",
        "schema": {
         "type": "integer"
        }
       }
      }
     }
    }
   }
  },
  "/api/v1/specialties": {
   "get": {
    "operationId": "listSpecialties",
    "summary": "Specialty names with doctor counts",
    "responses": {
     "200": {
      "description": "JSON result (same as the MCP tool's result)",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "provider": {
           "$ref": "#/components/schemas/Provider"
          },
          "official_french": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "name": {
              "type": "string"
             },
             "doctors": {
              "type": "integer"
             }
            }
           }
          },
          "english_labels": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "name": {
              "type": "string"
             },
             "doctors": {
              "type": "integer"
             }
            }
           }
          },
          "note": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "bad arguments, or the search was too broad (too_slow): the message says what to change",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "the Authorization header was sent but is invalid or expired (invalid_token): send no header or a valid account key",
      "headers": {
       "WWW-Authenticate": {
        "schema": {
         "type": "string"
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "rate_limited (too many requests) or daily_limit (daily doctor limit reached); the message says when it resets",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "headers": {
       "Retry-After": {
        "description": "seconds to wait",
        "schema": {
         "type": "integer"
        }
       }
      }
     },
     "500": {
      "description": "internal error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "busy or starting (busy, unavailable): retry after Retry-After",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "headers": {
       "Retry-After": {
        "description": "seconds to wait",
        "schema": {
         "type": "integer"
        }
       }
      }
     }
    }
   }
  },
  "/api/v1/about": {
   "get": {
    "operationId": "aboutDatabase",
    "summary": "Sources, licences, read dates, coverage and caveats",
    "responses": {
     "200": {
      "description": "JSON result (same as the MCP tool's result)",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "provider": {
           "$ref": "#/components/schemas/Provider"
          },
          "name": {
           "type": "string"
          },
          "edition": {
           "type": "string"
          },
          "version": {
           "type": "string"
          },
          "built_at_utc": {
           "type": "string"
          },
          "counts": {
           "type": "object"
          },
          "sources": {
           "type": "array",
           "items": {
            "type": "object"
           }
          },
          "coverage": {
           "type": "string"
          },
          "what_is_not_here": {
           "type": "string"
          },
          "ranking": {
           "type": "string"
          },
          "transparence_sante": {
           "type": "string"
          },
          "corrections": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "bad arguments, or the search was too broad (too_slow): the message says what to change",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "the Authorization header was sent but is invalid or expired (invalid_token): send no header or a valid account key",
      "headers": {
       "WWW-Authenticate": {
        "schema": {
         "type": "string"
        }
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "rate_limited (too many requests) or daily_limit (daily doctor limit reached); the message says when it resets",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "headers": {
       "Retry-After": {
        "description": "seconds to wait",
        "schema": {
         "type": "integer"
        }
       }
      }
     },
     "500": {
      "description": "internal error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "busy or starting (busy, unavailable): retry after Retry-After",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "headers": {
       "Retry-After": {
        "description": "seconds to wait",
        "schema": {
         "type": "integer"
        }
       }
      }
     }
    }
   }
  }
 }
}