{"openapi":"3.1.0","info":{"title":"Medaro AI API","version":"1","summary":"Read-only catalogue of medical organizations in Armenia for AI assistants.","description":"Public JSON API of medaro.am: clinics, hospitals, pharmacies and laboratories in Armenia (Yerevan and other cities) with contacts, hours, legal details, external ratings and state health-insurance (UHIF) tariffs, plus a symptom → which doctor navigator. Pharmacy chains are a separate record type (a brand grouping of pharmacies, not a legal entity), and `/changes` is an incremental feed so a consumer can refresh a copy without re-reading the catalogue. No authentication. Every organization carries a `provenance` block (recorded check, its date, the source URL) so an assistant can tell a checked record from an unchecked one. The API returns nothing that is absent from the public HTML page — in particular no registered legal address. Data from medaro.am may be used in answers with attribution to \"medaro.am\" and a link to the organization page (see `urls`). Bulk export of the whole catalogue — by agreement with info@medaro.am.","contact":{"name":"Medaro","email":"info@medaro.am","url":"https://medaro.am"},"x-attribution":"Data from medaro.am may be used in answers with attribution to \"medaro.am\" and a link to the organization page (see `urls`). Bulk export of the whole catalogue — by agreement with info@medaro.am.","x-llms-txt":"https://medaro.am/llms.txt"},"servers":[{"url":"https://medaro.am","description":"Production"}],"paths":{"/api/ai/v1":{"get":{"operationId":"getIndex","summary":"API index: endpoints, links, attribution","responses":{"200":{"description":"Index","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Index"}}}}}}},"/api/ai/v1/organizations":{"get":{"operationId":"listOrganizations","summary":"List organizations (clinics, hospitals, pharmacies, labs) and, on request, pharmacy chains","parameters":[{"name":"type","in":"query","description":"Type(s), comma-separated: clinic, hospital, pharmacy, lab, pharmacy-chain. `pharmacy-chain` is not an organization but a brand grouping of pharmacies, and it is returned only when asked for by name: a request without `type` still returns organizations only, and `type=pharmacy` still returns exactly pharmacies. An unknown value is a 400, never a silently empty page.","schema":{"type":"string","example":"clinic,hospital"}},{"name":"q","in":"query","description":"Case-insensitive substring search in names (hy/ru/en) and former names (aliases) in every language. Spaces and the № sign are ignored («поликлиника 17» = «Поликлиника №17»).","schema":{"type":"string","minLength":1}},{"name":"city","in":"query","description":"City slug. No value = all cities (the site's catalogue pages default to Yerevan). Unknown slug → 400 with the allowed list.","schema":{"type":"string","enum":["yerevan","gyumri","vanadzor","abovyan","vagharshapat","hrazdan","kapan","sevan","dilijan","ijevan","goris","armavir","artashat","ashtarak","gavar","masis","charentsavan","stepanavan","alaverdi","sisian","jermuk","yeghegnadzor","spitak","artik","meghri","byureghavan","aparan","martuni","noyemberyan","vedi","talin","tashir","berd","ararat","metsamor","nor-hachn","maralik"]}},{"name":"district","in":"query","description":"Yerevan district slug (kentron, arabkir, avan, davtashen, erebuni, ajapnyak, kanaker-zeytun, malatia-sebastia, nor-nork, nork-marash, nubarashen, shengavit). Districts exist only in Yerevan.","schema":{"type":"string"}},{"name":"insurance","in":"query","description":"1 — only organizations that accept state health insurance (UHIF).","schema":{"type":"string","enum":["1","0"]}},{"name":"chain","in":"query","description":"Pharmacy-chain slug: narrows the list to the branches of that chain. Chain membership is derived from the organization slug prefix, so only pharmacies can belong to one, and the chain's own record is excluded from the result. An unknown slug is a 400 listing the allowed values — a typo must not look like a chain with no branches. `district`, `insurance` and `chain` never return chain records: a chain has no district, no insurance flag and no chain of its own.","schema":{"type":"string","enum":["alfa-pharm","natali-pharm","vaga-pharm","tonus-pharm","gedeon-richter","theopharma","asteria","esculap","pharm-center","36-6","akg","levon-lamara","emily-pharm"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","description":"Position paging, kept for clients that already use it. On a live catalogue prefer `cursor`: an edit between two pages shifts every offset after it.","schema":{"type":"integer","minimum":0,"default":0}},{"name":"cursor","in":"query","description":"Opaque keyset cursor: pass back `next_cursor` from the previous response unchanged and never parse it. It records which record was last served, not how many to skip, so records added or removed between pages cause neither duplicates nor gaps. Valid only with the same filters (`type`, `q`, `district`, `insurance`, `chain`): the key includes the relevance of `q`. Given together with `offset`, the cursor wins and the response `offset` reports where it landed. A cursor from another endpoint or a mangled one is a 400.","schema":{"type":"string"}}],"responses":{"200":{"description":"Page of organizations (and pharmacy chains, if requested)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationList"}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/ai/v1/organizations/{slug}":{"get":{"operationId":"getOrganization","summary":"Organization card with legal details, external ratings and insurance tariffs — or a pharmacy chain card","description":"The same path serves a pharmacy chain when the slug is a chain slug (for example `alfa-pharm`). An organization slug always wins: the chain registry is consulted only after the catalogue has no such record. Unknown or hidden slug → 404.","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","example":"erebuni-medical-center"}}],"responses":{"200":{"description":"Organization or pharmacy chain","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/OrganizationDetail"},{"$ref":"#/components/schemas/PharmacyChainDetail"}]}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/ai/v1/changes":{"get":{"operationId":"listChanges","summary":"Incremental feed of catalogue changes, oldest change first","description":"Refresh a copy of the catalogue without re-reading it: ask with `since`, then follow `next_cursor` until it is null. The feed carries no card content — slug, type, `op`, the change date and the page URLs, nothing else. Ordered by `updated_at`, then `slug`. Medaro edits data in waves, so hundreds of records can share one `updated_at`: page with the cursor, never by moving `since` forward. What the feed cannot tell you is in `includes_deletions` and `note` — read them before trusting the result as a complete diff.","parameters":[{"name":"since","in":"query","description":"Lower bound on `updated_at`, INCLUSIVE. ISO 8601: a date (`2026-09-01` — midnight), or a timestamp with or without a zone (`2026-09-01T12:30:00Z`, `2026-09-01 12:30:00`); no zone means UTC, not server-local time. Sub-millisecond precision is truncated downwards, so a record on the boundary is never lost. Omitted — the feed starts from the beginning. Anything else is a 400.","schema":{"type":"string","example":"2026-09-01"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500,"default":200}},{"name":"cursor","in":"query","description":"Opaque keyset cursor over (`updated_at`, `slug`): pass back `next_cursor` unchanged. Together with `since` both apply — `since` stays the filter, the cursor is the position inside it. Cursors of this endpoint and of /organizations are not interchangeable.","schema":{"type":"string"}}],"responses":{"200":{"description":"Page of changes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangesPage"}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/ai/v1/conditions":{"get":{"operationId":"listConditions","summary":"\"Symptom → which doctor\" articles (navigation only)","responses":{"200":{"description":"All articles","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConditionList"}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/ai/v1/specialties":{"get":{"operationId":"listSpecialties","summary":"Medical specialties: names, synonyms, related articles","description":"Reference list used to match a patient's complaint to a kind of specialist, and from there to an article or an organization. Only specialties that exist in Medaro's reference table are returned.","parameters":[{"name":"q","in":"query","description":"Search in specialty titles (hy/ru/en) and synonyms. Whole words are matched first, in any grammatical form (\"гинеколога\", \"gynecology\", \"ակնաբույժի\"); when a specialty is recognised, exactly those specialties are returned. Otherwise falls back to substring search; case, spaces and the № sign are ignored. Omit to get the whole list.","schema":{"type":"string","minLength":2}},{"name":"locale","in":"query","description":"Adds a `label` in this language to every item.","schema":{"type":"string","enum":["hy","ru","en"]}}],"responses":{"200":{"description":"Specialties","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpecialtyList"}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/ai/v1/search":{"get":{"operationId":"search","summary":"Unified search across organizations and conditions","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":2}},{"name":"locale","in":"query","description":"Adds a `label` in this language to every hit.","schema":{"type":"string","enum":["hy","ru","en"]}}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResult"}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/ai/v1/openapi.json":{"get":{"operationId":"getOpenApi","summary":"This document","responses":{"200":{"description":"OpenAPI 3.1 document","content":{"application/json":{"schema":{"type":"object"}}}}}}}},"components":{"schemas":{"Localized":{"type":"object","description":"Text in three languages; null when a translation is missing (fallback order hy → ru → en).","properties":{"hy":{"type":["string","null"]},"ru":{"type":["string","null"]},"en":{"type":["string","null"]}},"required":["hy","ru","en"]},"LocaleUrls":{"type":"object","description":"Absolute page URLs per locale.","properties":{"hy":{"type":"string","format":"uri"},"ru":{"type":"string","format":"uri"},"en":{"type":"string","format":"uri"}},"required":["hy","ru","en"]},"Error":{"type":"object","properties":{"error":{"type":"string","enum":["bad_request","not_found","unavailable"]},"message":{"type":"string"}},"required":["error","message"]},"Rating":{"type":["object","null"],"description":"Medaro rating from the organization's own reviews. Present only when reviews_total ≥ 3; otherwise null. Ratings are never sold.","properties":{"value":{"type":"number","minimum":0,"maximum":5},"reviews_total":{"type":"integer","minimum":0},"reviews_verified":{"type":"integer","minimum":0,"description":"Reviews with a confirmed visit."}},"required":["value","reviews_total","reviews_verified"]},"Provenance":{"type":"object","description":"Where this record's public facts come from and when they were last reconciled with that source. Nothing here is inferred: a record with no recorded check returns verified=false and nulls rather than a guess.","properties":{"verified":{"type":"boolean","description":"true — Medaro's editorial process has checked this organization's public facts (name, address, phones, hours) against `source_url`, and the date of that check is in `verified_at`. false — no check is recorded: the record may still be correct, but Medaro does not vouch for it. The flag says what is recorded, never what is assumed."},"verified_at":{"type":["string","null"],"description":"ISO date of the last check (YYYY-MM-DD); null when none is recorded.","examples":["2026-08-22"]},"source_url":{"type":["string","null"],"format":"uri","description":"The source the facts were taken from and checked against — the organization's own site, spyur.am, the State Register, uhif.am, OpenStreetMap. null when no source is recorded."}},"required":["verified","verified_at","source_url"]},"Organization":{"type":"object","properties":{"slug":{"type":"string"},"type":{"type":"string","enum":["clinic","hospital","pharmacy","lab"]},"name":{"$ref":"#/components/schemas/Localized"},"address":{"$ref":"#/components/schemas/Localized"},"city":{"type":"string","enum":["yerevan","gyumri","vanadzor","abovyan","vagharshapat","hrazdan","kapan","sevan","dilijan","ijevan","goris","armavir","artashat","ashtarak","gavar","masis","charentsavan","stepanavan","alaverdi","sisian","jermuk","yeghegnadzor","spitak","artik","meghri","byureghavan","aparan","martuni","noyemberyan","vedi","talin","tashir","berd","ararat","metsamor","nor-hachn","maralik"],"description":"City slug (yerevan, gyumri, vanadzor…)."},"district":{"type":["string","null"],"description":"Yerevan district slug; null outside Yerevan."},"phones":{"type":"array","items":{"type":"string"}},"hours":{"allOf":[{"$ref":"#/components/schemas/Localized"}],"description":"Human-readable opening hours, e.g. \"Mon–Fri 09:00–18:00\" or \"24/7\"."},"hours_by_day":{"type":["object","null"],"description":"Raw schedule by weekday (mon…sun → \"09:00-18:00\").","additionalProperties":{"type":"string"}},"location":{"type":["object","null"],"properties":{"lat":{"type":"number"},"lng":{"type":"number"}},"required":["lat","lng"]},"accepts_insurance":{"type":"boolean","description":"Accepts state health insurance (UHIF)."},"ownership":{"type":"string","enum":["private","state"]},"website":{"type":["string","null"],"format":"uri"},"email":{"type":["string","null"],"format":"email","description":"Contact e-mail the organization publishes itself (its website, Spyur, its social page), lower-cased; the same address as the mailto link in the page's Contacts. Stored only together with the source URL and the date it was seen there. null means none is confirmed — not a gap to fill in with a guessed address. Personal mailboxes of staff are never listed.","examples":["info@example.am"]},"logo":{"type":["string","null"],"format":"uri","description":"Absolute logo URL (own logo or pharmacy-chain logo) or null."},"rating":{"$ref":"#/components/schemas/Rating"},"updated_at":{"type":["string","null"],"description":"When this record was last changed in the database (ISO 8601 with time and zone). Not the same event as `provenance.verified_at`, which is when the facts were reconciled with a source: a record can change without a new check, and be re-checked without changing. Use this one to sync (see /changes). null only when no timestamp exists.","examples":["2026-09-11T14:20:05.277172+00:00"]},"provenance":{"$ref":"#/components/schemas/Provenance"},"chain":{"$ref":"#/components/schemas/ChainRef"},"urls":{"$ref":"#/components/schemas/LocaleUrls"}},"required":["slug","type","name","address","city","district","phones","hours","hours_by_day","location","accepts_insurance","ownership","website","email","logo","rating","updated_at","provenance","chain","urls"]},"OrganizationList":{"type":"object","properties":{"count":{"type":"integer","description":"Total matching records — organizations, plus pharmacy chains when they were asked for in `type`."},"limit":{"type":"integer"},"offset":{"type":"integer","description":"Where this page starts. With `cursor` it is not the value you sent but the position the cursor landed on."},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` to get the next page; null means this was the last one. Opaque — do not parse or build one."},"items":{"type":"array","description":"Organizations and — only when `type` asked for them — pharmacy chains. Tell them apart by `type`; ordering puts chains last.","items":{"oneOf":[{"$ref":"#/components/schemas/Organization"},{"$ref":"#/components/schemas/PharmacyChain"}]}}},"required":["count","limit","offset","next_cursor","items"]},"Legal":{"type":["object","null"],"description":"Legal entity details from the State Register of Legal Entities of Armenia (e-register.moj.am) and other cited sources; null when unknown. The same fields the public HTML page shows. The registered legal address is NOT part of this API: it is absent from the page, and for many companies the register holds the director's home address there.","properties":{"legal_name":{"oneOf":[{"$ref":"#/components/schemas/Localized"},{"type":"null"}]},"tax_id":{"type":["string","null"],"description":"Tax id (ՀՎՀՀ / ИНН)."},"reg_number":{"type":["string","null"],"description":"State register number."},"director":{"type":["object","null"],"properties":{"name":{"$ref":"#/components/schemas/Localized"},"title":{"oneOf":[{"$ref":"#/components/schemas/Localized"},{"type":"null"}]}},"required":["name","title"]},"registry_url":{"type":["string","null"],"format":"uri","description":"Company card in the State Register (always the Armenian version)."},"sources":{"type":"array","items":{"type":"string","format":"uri"},"description":"URLs confirming the facts."},"fetched_at":{"type":["string","null"],"description":"When the facts were last verified (ISO 8601)."}},"required":["legal_name","tax_id","reg_number","director","registry_url","sources","fetched_at"]},"ExternalRating":{"type":"object","properties":{"source":{"type":"string","enum":["google","yandex","2gis"]},"rating":{"type":"number","minimum":0,"maximum":5},"reviews_count":{"type":"integer","minimum":0},"url":{"type":"string","format":"uri"},"fetched_at":{"type":["string","null"],"description":"ISO date of the snapshot."}},"required":["source","rating","reviews_count","url","fetched_at"]},"InsuranceService":{"type":"object","description":"A service covered by the state health-insurance programme (UHIF tariff, not the organization's private price list). Amounts in Armenian drams.","properties":{"code":{"type":["string","null"],"description":"UHIF tariff code."},"group":{"$ref":"#/components/schemas/Localized"},"name":{"allOf":[{"$ref":"#/components/schemas/Localized"}],"description":"hy is the official UHIF text; ru is Medaro's translation."},"compensation_amd":{"type":["integer","null"],"description":"Paid by the fund."},"copay_amd":{"type":["integer","null"],"description":"Patient co-payment; null — none."},"copay_is_max":{"type":"boolean","description":"true — copay_amd is an upper bound (\"up to\")."}},"required":["code","group","name","compensation_amd","copay_amd","copay_is_max"]},"InsuranceServices":{"type":"object","properties":{"total":{"type":"integer","description":"Total services of the organization in the programme."},"items":{"type":"array","maxItems":300,"items":{"$ref":"#/components/schemas/InsuranceService"}},"source":{"type":["object","null"],"description":"Where the tariffs come from (uhif.am) and when they were fetched.","properties":{"url":{"type":"string","format":"uri"},"fetched_at":{"type":["string","null"]}},"required":["url","fetched_at"]}},"required":["total","items","source"]},"OrganizationDetail":{"allOf":[{"$ref":"#/components/schemas/Organization"},{"type":"object","properties":{"aliases":{"type":["object","null"],"description":"Former and popular names by language.","properties":{"hy":{"type":"array","items":{"type":"string"}},"ru":{"type":"array","items":{"type":"string"}},"en":{"type":"array","items":{"type":"string"}}}},"is_dispatch_service":{"type":"boolean","description":"Ambulance-like dispatch service: you call it, you do not visit the address."},"legal":{"$ref":"#/components/schemas/Legal"},"external_ratings":{"type":"array","items":{"$ref":"#/components/schemas/ExternalRating"}},"insurance_services":{"$ref":"#/components/schemas/InsuranceServices"}},"required":["aliases","is_dispatch_service","legal","external_ratings","insurance_services"]}]},"ChainRef":{"type":["object","null"],"description":"The pharmacy chain a branch belongs to; null for clinics, hospitals, laboratories and pharmacies outside a chain. Membership is derived from the slug prefix — the database has no chain column — which is why only pharmacies are ever matched.","properties":{"slug":{"type":"string","examples":["alfa-pharm"]},"name":{"$ref":"#/components/schemas/Localized"},"url":{"type":"string","format":"uri","description":"The chain's own card in this API."},"urls":{"$ref":"#/components/schemas/LocaleUrls"}},"required":["slug","name","url","urls"]},"PharmacyChain":{"type":"object","description":"A pharmacy chain: a grouping of medaro.am pharmacy records by brand, not a legal entity and not a database row. It has no phone and no address — those belong to the branches. Appears in /organizations only when `type=pharmacy-chain` is requested, and always after the organizations.","properties":{"slug":{"type":"string","examples":["alfa-pharm"]},"type":{"type":"string","enum":["pharmacy-chain"]},"name":{"allOf":[{"$ref":"#/components/schemas/Localized"}],"description":"The spelling the branches themselves use in the catalogue, not an official brand book."},"branch_count":{"type":"integer","minimum":0,"description":"Active pharmacies of this chain in the catalogue right now — counted live on every request, never stored."},"branches_url":{"type":"string","format":"uri","description":"Ready-made request for all branches of this chain (one page covers the largest chain)."},"site":{"type":["string","null"],"format":"uri","description":"Official website, only where a source confirms one. null is not a gap to fill in: two chains (36.6, AKG) have no website at all and live on social accounts, and for two more (Levon & Lamara, Emily Pharm) nothing is confirmed."},"logo":{"type":["string","null"],"format":"uri","description":"Absolute URL of the chain's mark, only where the source is recorded; null for the two chains whose mark is not confirmed."},"company":{"type":["string","null"],"description":"Legal owner of the chain, in the source's own spelling, where confirmed — null otherwise (most chains). Never translated."},"socials":{"type":"array","items":{"type":"string","format":"uri"},"description":"Official social accounts, recorded for the chains that have no website; empty for the rest."},"updated_at":{"type":"null","description":"Always null: a chain is a registry entry in code, not a catalogue record, so there is no change timestamp to report. Its branches have one each."},"urls":{"$ref":"#/components/schemas/LocaleUrls"}},"required":["slug","type","name","branch_count","branches_url","site","logo","company","socials","updated_at","urls"]},"PharmacyChainDetail":{"allOf":[{"$ref":"#/components/schemas/PharmacyChain"},{"type":"object","properties":{"note":{"type":"string","description":"What a chain is in this data — read it before treating one as a company: no phone, no tax id, branch count counted live, missing site/logo/company mean unconfirmed, not absent."}},"required":["note"]}]},"Change":{"type":"object","description":"One catalogue record that changed. Deliberately no card content: this is the only listing that may ever include a record taken down, and a tombstone must not leak what the card said.","properties":{"type":{"type":"string","enum":["clinic","hospital","pharmacy","lab"]},"slug":{"type":"string"},"op":{"type":"string","enum":["created","updated","deleted"],"description":"Relative to `since`, not an absolute history: \"created\" — the record appeared in the catalogue after `since` (without `since` every live record counts as new, because the consumer has no copy yet); \"updated\" — it existed before `since` and changed; \"deleted\" — it is no longer published. Creation and update are told apart by the record's creation date, not by comparing timestamps: waves of edits have already overwritten `updated_at` on almost every record, so that comparison would call the whole catalogue new. See `includes_deletions` for when \"deleted\" can appear at all."},"updated_at":{"type":"string","description":"When the record was last changed (ISO 8601 with zone). For a removed record this is at or after the moment it was taken down.","examples":["2026-09-11T14:20:05.277172+00:00"]},"urls":{"allOf":[{"$ref":"#/components/schemas/LocaleUrls"}],"description":"Pages of the record. For a removed record they answer 404 — they are there to identify unambiguously what to drop."}},"required":["type","slug","op","updated_at","urls"]},"ChangesPage":{"type":"object","properties":{"since":{"type":["string","null"],"description":"The normalized UTC bound actually applied, or null.","examples":["2026-09-01T00:00:00.000Z"]},"limit":{"type":"integer"},"includes_deletions":{"type":"boolean","description":"Whether removed records can appear in this feed at all. While it is false the feed reports only published records, so removals are missing from it — re-read the full slug list from /organizations now and then and drop what is gone. The flag is computed per request, not hard-coded: it turns true by itself once tombstones become readable."},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; null — no more pages."},"note":{"type":"string","description":"The same warnings in prose, so an agent reading only the response still learns what `op` means and what the feed omits."},"items":{"type":"array","items":{"$ref":"#/components/schemas/Change"}}},"required":["since","limit","includes_deletions","next_cursor","note","items"]},"SpecialtyRef":{"type":"object","properties":{"code":{"type":"string","example":"neurologist"},"title":{"oneOf":[{"$ref":"#/components/schemas/Localized"},{"type":"null"}]}},"required":["code","title"]},"Specialty":{"type":"object","description":"A medical specialty from Medaro's reference table, with the entry points that actually hold content for it.","properties":{"code":{"type":"string","description":"Stable code; the site filters doctors by it.","examples":["neurologist"]},"title":{"$ref":"#/components/schemas/Localized"},"synonyms":{"type":"array","items":{"type":"string"},"description":"Alternative names in any of the three languages, in one flat list («ЛОР», «отоларинголог», \"ENT specialist\") — the data layer does not keep them separated by language. Empty when none are recorded."},"conditions":{"type":"array","description":"\"Symptom → which doctor\" articles that lead to this specialist. primary=true — the article's main specialist (its call to action).","items":{"type":"object","properties":{"slug":{"type":"string"},"title":{"$ref":"#/components/schemas/Localized"},"primary":{"type":"boolean"},"urls":{"$ref":"#/components/schemas/LocaleUrls"}},"required":["slug","title","primary","urls"]}},"doctors_count":{"type":"integer","minimum":0,"description":"Doctor profiles published on medaro.am for this specialty. 0 — none are published; use `conditions` and /organizations instead."},"doctors_urls":{"oneOf":[{"$ref":"#/components/schemas/LocaleUrls"},{"type":"null"}],"description":"Filtered doctor listing per locale. null whenever doctors_count is 0 — an empty listing is a dead end, so the link is not offered."},"label":{"type":["string","null"],"description":"Title in the requested locale (only when `locale` is given)."}},"required":["code","title","synonyms","conditions","doctors_count","doctors_urls"]},"SpecialtyList":{"type":"object","properties":{"count":{"type":"integer"},"query":{"type":["string","null"],"description":"The `q` that was applied, or null."},"locale":{"type":["string","null"],"enum":["hy","ru","en",null]},"disclaimer":{"type":"string","description":"Navigational use only — keep it when reusing this mapping."},"note":{"type":"string","description":"What this endpoint deliberately does not answer: Medaro's data holds no organization ↔ specialty link, so no clinic is claimed to employ a given specialist."},"items":{"type":"array","items":{"$ref":"#/components/schemas/Specialty"}}},"required":["count","query","locale","disclaimer","note","items"]},"Condition":{"type":"object","description":"A \"symptom → which doctor\" article. Navigation only: no diagnoses, treatment plans or dosages. Keep red_flags and the disclaimer when reusing.","properties":{"slug":{"type":"string"},"category":{"type":"string"},"title":{"$ref":"#/components/schemas/Localized"},"summary":{"$ref":"#/components/schemas/Localized"},"specialties":{"type":"array","description":"First item is the primary specialist.","items":{"$ref":"#/components/schemas/SpecialtyRef"}},"red_flags":{"type":"array","description":"When to seek urgent care (call 103 in Armenia).","items":{"$ref":"#/components/schemas/Localized"}},"urls":{"$ref":"#/components/schemas/LocaleUrls"}},"required":["slug","category","title","summary","specialties","red_flags","urls"]},"ConditionList":{"type":"object","properties":{"count":{"type":"integer"},"disclaimer":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/Condition"}}},"required":["count","disclaimer","items"]},"SearchResult":{"type":"object","properties":{"query":{"type":"string"},"locale":{"type":["string","null"],"enum":["hy","ru","en",null]},"organizations":{"type":"array","maxItems":20,"items":{"allOf":[{"$ref":"#/components/schemas/Organization"},{"type":"object","properties":{"label":{"type":["string","null"],"description":"Name in the requested locale (only when locale is given)."}}}]}},"conditions":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/Condition"},{"type":"object","properties":{"label":{"type":["string","null"],"description":"Title in the requested locale (only when locale is given)."}}}]}}},"required":["query","locale","organizations","conditions"]},"Index":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"version":{"type":"string"},"locales":{"type":"array","items":{"type":"string"}},"organization_types":{"type":"array","items":{"type":"string","enum":["clinic","hospital","pharmacy","lab"]},"description":"The kinds of organization in the catalogue — four, and a pharmacy chain is not one of them."},"list_types":{"type":"array","items":{"type":"string","enum":["clinic","hospital","pharmacy","lab","pharmacy-chain"]},"description":"What /organizations accepts in `type`: the organization types plus `pharmacy-chain`, which has to be asked for by name."},"endpoints":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"method":{"type":"string"},"params":{"type":"object","additionalProperties":{"type":"string"}},"returns":{"type":"string"}},"required":["path","method","params","returns"]}},"attribution":{"type":"string"},"links":{"type":"object","properties":{"llms":{"type":"string","format":"uri"},"agents":{"type":"string","format":"uri","description":"agents.md — what an agent can and cannot do here."},"sitemap":{"type":"string","format":"uri","description":"Sitemap index: a list of section sitemaps, not of pages."},"agentic_sitemap":{"type":"string","format":"uri","description":"Machine entry points as a sitemap (a child of the index)."},"openapi":{"type":"string","format":"uri"},"site":{"type":"string","format":"uri"}},"required":["llms","sitemap","openapi","site"]},"contact":{"type":"string","format":"email"}},"required":["name","description","version","locales","endpoints","attribution","links","contact"]}}}}