{"openapi":"3.1.0","info":{"title":"eUput — Serbian National Laboratory Services Registry API","version":"1.0.0","description":"The Serbian national laboratory-services registry (eUput) exposes a REST API for integrating hospital (BIS), laboratory (LIS) and referral systems. All responses are JSON. All data derives from the national nomenclature: NLU services (NLU-XXXX), NLK components (NLK-XXXX), LOINC and RFZO L-code links, sampling types (TU-XXX) and per-institution local mappings.\n\nLive /api/registry/* calls accept TWO credential shapes on the x-api-key header. (1) Institution key (eup_ prefix): sent WITH x-institution-id (the institution's numeric id), issued by the registry administrator during onboarding — valid on all endpoints including local-code resolution (/resolve). (2) GENERAL system key (eur_ prefix): for BIS/ZIS and other external consumers, sent ALONE (no x-institution-id), valid on national read endpoints (service lists, institutions for a service, institution search, changelog, translate) — NOT valid on /resolve. One of them is the MAIN key of the Centralni eUput sistem (kind 'central', at most one active): eUput Lab uses it for every national endpoint and reserves capacity in every laboratory for each CEU. Keys are NEVER public and must not ship in client-side (browser) code. Exceptions to the key rule: GET /api/registry/export/manifest is fully PUBLIC (no key), and GET /api/registry/export is SCOPED — it works without a key (public content scope: clean NLU/NLK nomenclature with no internal identifiers), while an institution key automatically widens the content. A call with a WRONG key always returns 401 — sent credentials are never silently downgraded to a lower scope."},"servers":[{"url":"https://BASE_URL","description":"Replace with the registry deployment URL"}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"x-api-key","description":"Institution API key issued at onboarding (private)."},"institutionId":{"type":"apiKey","in":"header","name":"x-institution-id","description":"The institution's numeric id."},"elabApiKey":{"type":"apiKey","in":"header","name":"x-elab-api-key","description":"System-level key for the national eLab system only."},"generalApiKey":{"type":"apiKey","in":"header","name":"x-api-key","description":"General system key (eur_ prefix) — the main key of the Centralni eUput sistem (eUput Lab, at most one active) or a BIS/ZIS consumer key — sent alone, WITHOUT x-institution-id. Valid on national read endpoints, lab capacity of any institution and radiology scheduling (not /resolve)."}}},"paths":{"/api/registry/services":{"get":{"operationId":"services-search","summary":"Search national services","description":"Main registry search. Search by whatever you have: NLU code, Serbian/English name (diacritic-insensitive), RFZO L-code, LOINC code or local LIS code. Also covers the indirect path: a LIS code confirmed only on an NLK component surfaces every panel containing it. Returns active services with LOINC/L-code links, sampling type and offering institutions.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"q","in":"query","required":false,"description":"Free text or any code (NLU, L-code, LOINC, local LIS).","schema":{"type":"string"}},{"name":"category","in":"query","required":false,"description":"Exact category (e.g. Biohemija).","schema":{"type":"string"}},{"name":"institution","in":"query","required":false,"description":"Institution code — only services that institution offers.","schema":{"type":"string"}},{"name":"hasLcode","in":"query","required":false,"description":"Filter by RFZO L-code coverage.","schema":{"type":"boolean"}},{"name":"limit","in":"query","required":false,"description":"Max results (default 25, max 100).","schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"description":"Pagination offset.","schema":{"type":"integer"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"total":3,"returned":1,"items":[{"code":"NLU-0022","displaySr":"Glukoza","category":"Biohemija","unit":"mmol/L","specimen":"Serum","samplingType":{"code":"TU-001","nameSr":"Venska krv — serum/plazma","specimenClass":"Serum/plazma","collectionMethod":"Venepunkcija"},"loinc":[{"code":"2345-7","display":"Glucose [Moles/volume] in Serum or Plasma"}],"lcodes":[{"code":"L000414","display":"Glukoza u serumu"}],"institutions":[{"code":"INST-881244","name":"Dom zdravlja Ljubovija","city":"Ljubovija","lisCode":"GLU-S"}]}]}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/services/{code}":{"get":{"operationId":"service-detail","summary":"Full service record","description":"Everything the registry knows about one NLU service: full medical identity (analyte, specimen, method, scale), sampling type, definitions, revision metadata, all code mappings (LOINC, L-codes), panel components with confirmed institution-mapping counts, and every institution offering the service (confirmed mapping) with its LIS codes.\n\norderedAs = the doctor-catalog item this NLU is ordered through: loinc is the canonical code (after alias folding — an erythrocyte NLU may be mapped to 26453-1 while the doctor picks 789-8), mappedLoinc the raw mapping from loinc[]; orderable=false ⇒ narrower/related mapping only (the service is shown under that code, never executed through it); null ⇒ the service has no LOINC and the doctor cannot pick it.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"code","in":"path","required":true,"description":"NLU service code (e.g. NLU-0022).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"service":{"code":"NLU-0022","displaySr":"Glukoza","identity":{"analyte":"Glukoza","specimen":"Serum","method":null,"scaleType":"Qn","unitUcum":"mmol/L"},"samplingType":{"code":"TU-001","nameSr":"Venska krv — serum/plazma","specimenClass":"Serum/plazma","collectionMethod":"Venepunkcija"},"meta":{"status":"active","revision":3},"loinc":[{"code":"2345-7","display":"..."}],"orderedAs":{"loinc":"2345-7","mappedLoinc":"2345-7","nameSr":"Glukoza u serumu/plazmi","nameEn":"Glucose [Moles/volume] in Serum or Plasma","equivalence":"equivalent","orderable":true,"catalog":"/api/registry/loinc/2345-7"},"lcodes":[{"code":"L000414","display":"..."}],"components":[],"institutions":[{"code":"INST-881244","name":"Dom zdravlja Ljubovija","city":"Ljubovija","type":"clinic","lisCodes":[{"lisCode":"GLU-S","lisDisplay":"Glukoza (serum)","kind":"direct"}]}]}}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/services/{code}/guidance":{"get":{"operationId":"service-guidance","summary":"Service guidance and preparation (doctor, patient, sampler)","description":"What a referral system shows as soon as a service is picked — split by audience and wizard step: doctor (indications, what to write on the referral, interpretation pitfalls; service-picking step), patient (what to expect, what to bring, when results arrive; referral and patient notice), sampler (tube, order of draw, processing, stability, rejection criteria; sampling step). SEPARATE from the recommendations is the structured preparation: required, fastingHours, leadTimeHours (when the preparation starts before the service), summary, steps (ordered patient steps), medications, contraindications (what the performer must check first), bring, afterCare. Items were AI-drafted from catalog data and reference guidelines (CLSI order of draw, ACR contrast manual, institutional preparation sheets) and are curated by the NRLU editor: source ai|editor and reviewed tell whether an item was reviewed — a client may label unreviewed items as an AI draft.\n\nThe same content is embedded in GET /api/registry/services/{code} (fields guidance and preparation).\nFor a whole referral at once use /api/registry/guidance (NLU and NRU codes together).","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"code","in":"path","required":true,"description":"NLU service code (e.g. NLU-0022).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"service":{"code":"NLU-0022","name":"Glukoza u serumu","domain":"lab"},"guidance":{"doctor":{"label":"Preporuka lekaru","step":"Korak „Usluge“ pri izboru analize","items":[{"id":1201,"text":"Tražiti natašte; za dijagnozu dijabetesa potvrditi ponovljenim merenjem ili HbA1c.","source":"ai","reviewed":false}]},"patient":{"label":"Preporuka pacijentu","step":"Uput i obaveštenje pacijentu","items":[{"id":1205,"text":"Vađenje krvi traje nekoliko minuta; nalaz je najčešće gotov istog dana.","source":"editor","reviewed":true}]},"sampler":{"label":"Preporuka uzorkivaču","step":"Korak uzorkovanja u punktu / laboratoriji","items":[{"id":1209,"text":"Fluorid/oksalat (sivi čep) ako se serum ne odvaja u roku od 30 min; poveska najviše 1 min.","source":"ai","reviewed":false}]}},"preparation":{"required":true,"fastingHours":8,"leadTimeHours":12,"summary":"Doći ujutru natašte; voda je dozvoljena.","steps":["Ne jesti 8–12 sati pre vađenja krvi.","Redovnu terapiju uzeti posle vađenja, osim ako lekar ne kaže drugačije."],"medications":null,"contraindications":[],"bring":["lista lekova"],"afterCare":null,"source":"ai","reviewed":false,"updatedAt":"2026-10-01T06:40:11.000Z"},"review":{"items":12,"reviewed":1,"pendingAi":11,"preparationPending":true}}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/rad/services/{code}/guidance":{"get":{"operationId":"rad-service-guidance","summary":"Radiology service guidance and preparation (NRU)","description":"Same shape as for NLU, for a national radiology service: doctor (indications, when another modality is better, what to write on the referral: clinical question, creatinine, allergies, pregnancy, implants), patient (what the exam is like, duration, what to bring, afterwards), sampler = PERFORMER (radiology technician — safety checks, positioning, protocol, contrast, radiation protection, laterality). Preparation is central in radiology: fasting before contrast / abdominal US, metformin and eGFR with iodinated contrast, MR safety (pacemaker, implants), full bladder, bowel prep, no deodorant for mammography, no calcium before DEXA, FDG PET fasting and glycaemia. Curated by the NRRU editor.\n\nReference content — unlike slot booking it is readable with an institution key (eup_) too.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"code","in":"path","required":true,"description":"NRU radiology service code (e.g. NRU-0010).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"service":{"code":"NRU-0120","name":"CT abdomena i male karlice, sa IV kontrastom","domain":"rad"},"guidance":{"doctor":{"label":"Preporuka lekaru (upućivaču)","step":"Korak „Usluge“ pri izboru pregleda","items":[{"id":9001,"text":"Na uput upisati kliničko pitanje, vrednost kreatinina/eGFR i ranije reakcije na jodni kontrast.","source":"ai","reviewed":false}]},"patient":{"label":"Preporuka pacijentu","step":"Uput, zakazivanje i obaveštenje pacijentu","items":[{"id":9005,"text":"Pregled traje 15–30 minuta; posle kontrasta pijte više tečnosti tokom dana.","source":"ai","reviewed":false}]},"sampler":{"label":"Preporuka izvođaču (radiološki tehničar)","step":"Korak izvođenja pregleda u radiološkoj ustanovi","items":[{"id":9009,"text":"Pre kontrasta proveriti eGFR, alergije i trudnoću; obezbediti venski put 18–20 G.","source":"ai","reviewed":false}]}},"preparation":{"required":true,"fastingHours":4,"leadTimeHours":48,"summary":"Ne jesti 4 sata pre pregleda; poneti nalaz kreatinina.","steps":["Ne jesti 4 sata pre pregleda; voda je dozvoljena.","Poneti nalaz kreatinina/eGFR ne stariji od 7 dana.","Prijaviti ranije alergijske reakcije na kontrast i moguću trudnoću."],"medications":"Metformin: ako je eGFR ≥ 30 nije potrebno prekidati; ako je eGFR < 30 prekinuti na dan pregleda i 48 h posle.","contraindications":["trudnoća","eGFR < 30","ranija reakcija na jodni kontrast"],"bring":["nalaz kreatinina/eGFR","prethodne snimke"],"afterCare":"Pojačan unos tečnosti 24 h.","source":"ai","reviewed":false,"updatedAt":"2026-10-01T06:52:03.000Z"},"review":{"items":15,"reviewed":0,"pendingAi":15,"preparationPending":true}}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/guidance":{"post":{"operationId":"guidance-batch","summary":"Guidance and preparation for a whole referral (many services at once)","description":"One call for every service on a referral — NLU and NRU codes may be mixed (up to 50). Returns the same per-service object as the single endpoints, unknown codes in missing, and a summary: which services need preparation (preparationRequired) and the longest fasting among them (maxFastingHours) — handy for one patient notice. Recommended flow: show guidance.doctor while picking; guidance.patient + preparation (steps, bring, medications) on the referral / patient notice; guidance.sampler + preparation.contraindications as a pre-procedure checklist at the performing site. Also available as GET ?codes=NLU-0022,NRU-0120.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"codes","in":"query","required":false,"description":"GET variant: comma-separated codes.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"services":[{"service":{"code":"NLU-0022","name":"Glukoza u serumu","domain":"lab"},"guidance":{"doctor":{"label":"Preporuka lekaru","step":"…","items":[]},"patient":{"label":"Preporuka pacijentu","step":"…","items":[]},"sampler":{"label":"Preporuka uzorkivaču","step":"…","items":[]}},"preparation":{"required":true,"fastingHours":8,"steps":["…"]},"review":{"items":12,"reviewed":1,"pendingAi":11,"preparationPending":true}},{"service":{"code":"NRU-0120","name":"CT abdomena i male karlice, sa IV kontrastom","domain":"rad"},"guidance":{},"preparation":{"required":true,"fastingHours":4},"review":{}}],"missing":["NLU-9999"],"summary":{"requested":3,"found":2,"preparationRequired":["NLU-0022","NRU-0120"],"maxFastingHours":8}}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["services"],"properties":{"services":{"description":"Service codes, NLU-… and/or NRU-… (1–50)."}}}}}}}},"/api/registry/services/{code}/institutions":{"get":{"operationId":"service-institutions","summary":"Institutions performing a service or component (referral)","description":"Purpose-built for REFERRAL CREATION: which live institutions can perform this? Works for BOTH national code kinds. For an NLU service/panel it returns institutions whose confirmed catalog mapping covers the service. For an NLK component it returns institutions that deliver the component directly (a LIS code confirmed on the NLK) OR indirectly via a containing panel — the via field distinguishes cases (direct | panel | both), and viaPanels lists which panels to order for indirect ones. Only live institutions, with coordinates for map display.\n\nFor NLU codes the response has kind=\"service\" and each institution carries lisCode instead of via/viaPanels.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"code","in":"path","required":true,"description":"NLU code (NLU-XXXX) or NLK code (NLK-XXXX).","schema":{"type":"string"}},{"name":"city","in":"query","required":false,"description":"City filter (case-insensitive exact match).","schema":{"type":"string"}},{"name":"type","in":"query","required":false,"description":"Institution type (laboratory | hospital | clinic | private).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"kind":"component","component":{"code":"NLK-0039","name":"Kalcijum"},"returned":24,"institutions":[{"code":"INST-881244","name":"Dom zdravlja Ljubovija","city":"Ljubovija","type":"clinic","latitude":44.23,"longitude":19.08,"via":"both","localCode":"K-155","viaPanels":[{"code":"NLU-0369","name":"Krvna slika (trodelna)","lisCode":"KKS"}]}]}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/institutions":{"get":{"operationId":"institutions-search","summary":"Search institutions","description":"General institution search for referral UIs: by name/code/city (diacritic-insensitive), type, and whether they actively offer a given NLU service. Only live institutions, each with coordinates and mappingCount as a size signal.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"q","in":"query","required":false,"description":"Free text over code, name, city.","schema":{"type":"string"}},{"name":"city","in":"query","required":false,"description":"Exact city.","schema":{"type":"string"}},{"name":"type","in":"query","required":false,"description":"Institution type.","schema":{"type":"string"}},{"name":"service","in":"query","required":false,"description":"NLU code — only institutions offering it.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Max results (default 25, max 100).","schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"description":"Pagination offset.","schema":{"type":"integer"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"total":1,"returned":1,"institutions":[{"code":"INST-881244","name":"Dom zdravlja Ljubovija","city":"Ljubovija","type":"clinic","latitude":44.23,"longitude":19.08,"mappingCount":412}]}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/institutions/nearest":{"get":{"operationId":"institutions-nearest","summary":"Nearest institutions (geo)","description":"For referral systems: live institutions ordered by distance from a point (Haversine great-circle), optionally filtered by radius, type and an NLU service they must offer.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"lat","in":"query","required":true,"description":"Latitude (-90..90).","schema":{"type":"number"}},{"name":"lng","in":"query","required":true,"description":"Longitude (-180..180).","schema":{"type":"number"}},{"name":"limit","in":"query","required":false,"description":"Max results (default 10, max 50).","schema":{"type":"integer"}},{"name":"maxKm","in":"query","required":false,"description":"Radius filter in kilometers.","schema":{"type":"number"}},{"name":"type","in":"query","required":false,"description":"Institution type.","schema":{"type":"string"}},{"name":"service","in":"query","required":false,"description":"NLU code — only institutions offering it.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"returned":2,"institutions":[{"code":"INST-881244","name":"Dom zdravlja Ljubovija","city":"Ljubovija","distanceKm":3.42,"latitude":44.23,"longitude":19.08}]}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/institutions/{code}/services/{concept}":{"get":{"operationId":"institution-service","summary":"How an institution performs a service (execution API)","description":"Execution API for LIS systems: \"what is NLU-XXXX at my site?\" Returns the institution's eLab catalog items mapped to that national service and, separately, lisCodes — the LIS šifarnik entries with a CONFIRMED decision on the same NLU (item.lisCode = the first of them). Multiple items = the institution distinguishes method variants; primary marks the default. Method choice happens HERE, at the execution site — never on the referral.\n\nFields localCode/localDisplay are DEPRECATED aliases of elabCode/elabDisplay — migrate to elabCode; LIS codes live in lisCodes.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"code","in":"path","required":true,"description":"Institution code or numeric eLab id.","schema":{"type":"string"}},{"name":"concept","in":"path","required":true,"description":"NLU service code.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"institution":{"code":"INST-881244","name":"Dom zdravlja Ljubovija"},"service":{"code":"NLU-0022","name":"Glukoza"},"returned":1,"items":[{"elabCode":"280","elabId":"1024","elabDisplay":"Glukoza u serumu","lisCode":"GLU-S","lisDisplay":"Glukoza (serum)","vendor":null,"method":null,"primary":true}],"lisCodes":[{"lisCode":"GLU-S","lisDisplay":"Glukoza (serum)"}]}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/sampling-plan":{"get":{"operationId":"sampling-plan","summary":"Sampling plan for a referral (containers)","description":"Recommended containers (tubes) for ONE patient visit: services sharing a container are pooled into one tube, tubes are sorted by phlebotomy order of draw, and each lists cap color, additive, volume, inversions and handling instructions. With the institution parameter the executing institution's container overrides are applied (institutionOverride). Services whose sampling type has no confirmed recommendation are listed under unplanned. This is a RECOMMENDATION of the national registry — the executing laboratory's own SOP has the final word.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"services","in":"query","required":true,"description":"Comma-separated NLU codes on the referral.","schema":{"type":"string"}},{"name":"institution","in":"query","required":false,"description":"Executing institution code — applies its container overrides; omitted = pure national recommendation.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"institution":"ELAB-374006","requested":2,"planned":2,"disclaimer":"Preporuka nacionalnog registra — konačnu odluku donosi SOP laboratorije izvršioca.","containers":[{"order":1,"code":"EPR-003","name":"Epruveta sa gelom (serum)","capColor":"Žuta","capColorHex":"#eab308","additive":"Aktivator koagulacije + gel","volume":"5 ml","inversions":5,"instructions":"Ostaviti 30 min da koaguliše pre centrifugiranja","institutionOverride":false,"overrideNote":null,"samplingTypes":[{"code":"TU-001","nameSr":"Venska krv — serum/plazma"}],"services":[{"conceptCode":"NLU-0022","displaySr":"Glukoza"}]}],"unplanned":[]}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/diagnoses/{sifra}/services":{"get":{"operationId":"diagnosis-services","summary":"Analyses for a diagnosis (ICD-10 → NLU)","description":"Ranked national laboratory services clinically linked to ONE ICD-10 diagnosis — for suggesting analyses while the referral is being written. Relevance grade 1–5 (5 key: part of the diagnostic criteria or the standard confirmatory test; 4 high: standard work-up/monitoring per guidelines; 3 moderate; 2 low; 1 marginal) with a derived verdict: supported (4–5), plausible (3), weak (1–2). A category (E11) inherits links of its subcategories and a subcategory (E11.9) those of its category (via: direct | parent:E11 | child:E11.2); inherit=0 returns only links stored on that exact code. Links are AI-built from the service side (one pass per NLU/NLK over the whole codebook) and curated by the NRLU editor (reviewed: true). An analysis NOT on the list has no support in the registry — that is not a prohibition; the registry does not know every indication. Chapters and groups (E10-E14) are not referable → 422.\n\nRoles: dijagnostika | pracenje | skrining | diferencijalna | komplikacije | terapija — why the analysis is ordered for that diagnosis.\nThe diagnosis codebook is ICD-10 (Batut 2010) from the eUput Šifarnik middleware; codes absent there (asterisk codes, ICD-10-CM extensions, U07.1) do not exist here either → 404.\nSeveral diagnoses plus the analyses already picked are checked by POST /api/registry/diagnoses/validate.\nview=loinc (the doctor's view): items[] = { loinc, displayName, kind, performedBy, relevance, verdict, supported, members[] } — one item per LOINC the doctor CAN pick (the /api/registry/loinc catalog rule: performed by at least one live institution in Serbia and an orderable code); item grade = best member. Order (rank): grade, then the number of institutions producing the result (performedBy — the widely available result ahead of a method-bound variant, e.g. serum glucose ahead of glucometer glucose), then name; render items in that order. A result-only NLK (MCV, casts) is listed under the panel that produces it (members[].viaPanel = true), as is a stand-alone NLU no institution the sample can reach performs while a panel carries it. withoutLoinc[] = analyses the doctor cannot order through LOINC: reason no_loinc | mapping_not_orderable (narrower/related mapping) | not_performed (nobody performs it) | performed_not_executable (performed only by institutions no sample can reach — they do not sample that specimen type themselves and no confirmed route brings it) | not_listed (code not orderable — notListedReason, and no panel produces it).\nview=loinc — GRADE PROVENANCE: every item carries via (direct | parent | child) and inheritedFrom. direct = at least one member is linked to the REQUESTED code; parent = the grade is inherited from the category (E11.9 ← E11: judged for all of type 2, not for 'without complications'); child = rolled up from a subcategory when a category is viewed. Show an inherited item as 'inherited from E11', not as this diagnosis's own key analysis; members[] carry onCode (the code the link is stored on) and rationale. inherit=0 returns direct links only.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"sifra","in":"path","required":true,"description":"ICD-10 category (E11) or subcategory (E11.9); the dot is optional (E119).","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Number of services, 1–50 (default 20).","schema":{"type":"integer"}},{"name":"min","in":"query","required":false,"description":"Lowest grade returned, 1–5 (default 1; 4 = supported only).","schema":{"type":"integer"}},{"name":"inherit","in":"query","required":false,"description":"1 (default) inherits parent/child links; 0 = exact code only.","schema":{"type":"string"}},{"name":"components","in":"query","required":false,"description":"1 adds components[] — NLK analytes linked to the diagnosis (measured inside panels).","schema":{"type":"string"}},{"name":"view","in":"query","required":false,"description":"national (default) = NLU/NLK list; loinc = the doctor's view — items[] per LOINC the doctor can pick (the catalog rule: performed by ≥1 institution, orderable code) with members[] (NLU variants, NLK components; viaPanel = a result-only member shown under its panel) + withoutLoinc[] with a reason.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"resourceType":"DiagnosisServiceRecommendation","diagnosis":{"code":"E11","level":"kategorija","name":"Šećerna bolest, insulinonezavisan oblik","nameLat":"Diabetes mellitus ad insulino independens","parent":"E10-E14","chapter":"IV","active":true},"filter":{"limit":20,"min":1,"inherit":true,"components":false},"total":96,"services":[{"rank":1,"code":"NLU-0263","name":"Hemoglobin A1c (glikohemoglobin, HbA1c) u krvi HPLC","type":"NLU","category":"Biohemija","relevance":5,"relevanceLabel":"Ključna","verdict":"supported","role":"dijagnostika","rationale":"Standardni test za dijagnozu i procenu kontrole šećerne bolesti tipa 2.","via":"direct","source":"ai","reviewed":false}],"scale":{"1":"Marginalna","2":"Niska","3":"Umerena","4":"Visoka","5":"Ključna"},"note":"Ocena 4–5 = analiza podržana dijagnozom, 3 = verovatna, 1–2 = slaba. Analiza koja nije na listi nema uporište u registru, što nije zabrana."}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/diagnoses/validate":{"post":{"operationId":"diagnosis-validate","summary":"Validate analyses against the referral's diagnoses","description":"For the referral's diagnoses (1–10) and the analyses the doctor picked (up to 100 NLU/NLK codes) returns, per analysis, the BEST grade across all diagnoses, the diagnosis carrying it (supportedBy) and a verdict supported | plausible | weak | unsupported, a summary, and suggestions — services graded ≥ minSuggest for any diagnosis that are NOT on the referral (what the doctor may be missing). Unknown, retired and non-referable codes (chapter/group) are reported in issues; the response is 200 while at least one diagnosis is usable, 422 otherwise. Intended as a warning and a hint while the referral is written, not a block: unsupported means \"no link in the registry\", not \"forbidden\".\n\nissues.issue: invalid_format | unknown_code | inactive_code | level_poglavlje_not_allowed | level_grupa_not_allowed.\nRecommended flow in a referral system: on diagnosis entry call GET …/diagnoses/{sifra}/services?min=4 for suggestions; before signing the referral call validate and show unsupported/weak analyses as a warning with the rationale.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"resourceType":"DiagnosisServiceValidation","diagnoses":[{"code":"E11.9","level":"potkategorija","name":"Šećerna bolest, insulinonezavisan oblik — Bez komplikacija","strongServices":["NLU-0263","NLU-0242","NLU-0016"]}],"issues":[{"code":"E10-E14","issue":"level_grupa_not_allowed"}],"services":[{"code":"NLU-0263","name":"Hemoglobin A1c (glikohemoglobin, HbA1c) u krvi HPLC","relevance":5,"relevanceLabel":"Ključna","verdict":"supported","supportedBy":"E11.9","role":"dijagnostika","rationale":"Standardni test za dijagnozu i procenu kontrole šećerne bolesti tipa 2.","reviewed":false},{"code":"NLU-0999","relevance":null,"relevanceLabel":null,"verdict":"unsupported","supportedBy":null,"role":null,"rationale":null}],"summary":{"supported":1,"plausible":0,"weak":0,"unsupported":1},"suggestions":[{"code":"NLU-0016","name":"Albumin (mikroalbuminurija) u dnevnom urinu, imunoturbidimetrija","type":"NLU","category":"Urin i telesne tečnosti","relevance":5,"relevanceLabel":"Ključna","role":"komplikacije","rationale":"Ključan test za skrining i praćenje dijabetičke nefropatije.","forDiagnosis":"E11.9"}],"note":"supported = ocena 4–5 uz bar jednu dijagnozu; plausible = 3; weak = 1–2; unsupported = registar nema vezu (nije zabrana). Predlozi su usluge sa ocenom ≥ minSuggest koje nisu na uputu."}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["diagnoses"],"properties":{"diagnoses":{"description":"ICD-10 codes on the referral (1–10), e.g. [\"E11.9\", \"I10\"]."},"services":{"description":"Picked analyses — NLU and/or NLK codes (up to 100). Empty = suggestions only."},"suggest":{"description":"Number of suggestions, 0–50 (default 10)."},"minSuggest":{"description":"Lowest grade for a suggestion, 1–5 (default 4 = supported only)."}}}}}}}},"/api/registry/lab-options":{"get":{"operationId":"lab-options","summary":"Best laboratory for a referral (ranked execution plans)","description":"Referral planner: for the referral items (the doctor's LOINC codes and/or NLU codes) and the patient's location it returns ranked execution plans within the requested window. A plan states WHERE and on WHICH DAY the patient is sampled, WHERE each analysis runs — at the same institution (kind=single) or shipped over a declared sample route to a partner laboratory (kind=split: courier weekday, cut-off, transit days, arrival date) — the expected result date (resultEta, only when the analysis rule carries a TAT) and the EXACT reserve calls that execute the plan. score 0–100 is transparent via scoreBreakdown (distance, waiting, hand-off, TAT, occupancy) so referral systems can re-weight it. Candidates are filtered by the institutions' day capacity — full and closed days are skipped. ONE SITE FIRST: every plan has one sampling site, and plans that execute the WHOLE referral from it (complete=true — every sampling type the services need and every analysis) always rank above partial ones; samplingPlan.verdict says whether one site can do it at all and, if not, why.\n\nA plan is a RECOMMENDATION — nothing is reserved until the referral system executes the reserve calls (in order, with the same referralRef in place of {referralRef}).\nkind=single: one reserve call (sampling + analyses at the same institution). kind=split: the first call reserves sampling (services: []), the following ones reserve analyses (samplings: 0) at the receiving laboratories.\nA sampling site never receives a service whose sampling type (TU) it switched off in the portal — such services are listed in coverage.notSampleable and the plan does not cover them.\nONE SITE FIRST: a plan is complete=true when that single sampling site takes EVERY sample the referral needs (no required TU switched off, per-TU quotas open that day) and every analysis has a performer (in-house or over a route). Complete plans always rank above partial ones regardless of score; a partial plan also carries secondSite −20 in scoreBreakdown (the patient must visit a second site). When the same institution has both partial and complete dates, the leading date is the earliest complete one.\nsamplingPlan (verdict for the whole referral): one_site = take option 1; one_site_other_window = some institution can do it all (sitesCoveringAll > 0) but no date in this window passes (quotas, horizon) — widen the window before splitting the referral; split_referral = no institution can execute the whole referral, blocker says why (sampling_types = nobody takes every required TU; analysis = the sites taking every sample cannot get every analysis done, in-house or over a confirmed route; uncovered = a service nobody performs) — only then does the referral system create two referrals at two sites, from the partial plans allowPartial=1 returns; none = nothing to execute. requiredTypes lists the TUs the referral needs and the services behind each.\nhome=1 (home sampling): candidates are only institutions offering home visits, within their radius from the patient's address; sampling.mode is \"home\", sampling.home carries conditions and radius, and the reserve calls carry mode: \"home\" — they drain the SEPARATE home-visit quota, not on-site places.\n\"OR\" OPERATOR (services=NLU-A,NLU-B|NLU-C): a group of alternatives is ONE requirement satisfied by any of them — the doctor does not mind which. For every sampling site the planner picks the alternative that site executes most simply (in-house before shipped, a sampling type the rest of the referral already needs before an extra tube, then the doctor's order) and, when the pick has no room that day (analysis quota, TU quota), tries another. A group therefore raises the chance of finding an institution that executes the WHOLE referral (complete). Result: requirements (echo, kind service | any_of), coverage.alternatives per option ({ requirement: \"NLU-B|NLU-C\", anyOf, chosen } — chosen = picked code, null when none fits); coverage.covered and the reserve calls carry the CONCRETE picked code; coverage.missing / notSampleable / uncoveredServices name the requirement (for a group the key \"NLU-B|NLU-C\"). samplingPlan.requiredTypes covers plain services, alternativeGroups lists each alternative's TU. A group containing a service also requested on its own is already satisfied and dropped; unknown codes in a group appear in unknownServices and requirements[].unknown.\nLOINC INPUT (the doctor's language): translation[] explains every LOINC on the referral — canonical (after alias folding), nameSr, kind (service | component | unknown), anyOf (the NLU variants the planner may execute; for a component the panels containing it, viaComponent), requirement (the requirement key it became; null when a separately requested NLU already covered it), reason (loinc_unknown | loinc_unmapped), listed/notListedReason (a code the doctor's catalog does not offer but the planner still executes — a panel member runs as its panel), performedBy (the number of institutions the planner can offer for the code — the same figure as availability.institutions in the catalog; 0 means the catalog does not offer it, so a missing option is a registry gap, not a scheduling one) and related (services linked too loosely — a stimulation test, a diurnal profile — that are NOT executed through this code). Per option: options[].loincResolution[] = { loinc, component, executedAt, allowed, chosen, available } — the LOINC UNFOLDED at the analysis institution: executedAt is the code of the laboratory executing it in this plan (the site itself or the routed laboratory), allowed are the variants THAT laboratory performs and THAT is what the referral system writes on the referral as allowed (allowed.length > 1 ⇒ its LIS picks the method and returns the executed NLU in the result), chosen is the variant the plan counts, component is the NLK result when the LOINC is a panel member (hemoglobin inside KKS — the referral carries panel + component), available is the wider set the site can get executed at all (in-house or over a route) — kept for older clients, NOT what goes on the referral as allowed.\nresultEta is null when the analysis rule carries no TAT; unknownServices lists unknown NLU codes, uncoveredServices codes no candidate laboratory performs.\nCITO FLOW (priority=urgent | cito=1): an urgent referral goes to the NEAREST institution REGARDLESS OF CAPACITY. A quota never rules a date out — a spent day / sampling-type sub-quota gives sampling.overQuota=true (free 0, state limited), a spent analysis rule analysis[].overQuota=true, and the reserve calls (priority: \"urgent\") are ACCEPTED over quota, returning reservation.overQuota with the overrun (a routine referral would get 409 full / sampling_type_full / analysis_full). Today remains a possible day even after every window ended — sampling.afterWindows=true means the urgent sample is taken outside routine hours. Ranking within the filijala: earliest day, then nearest site (score stays informational). The filijala rule is the same as for a routine referral: the patient's filijala first, outside it (home_plus_nearby / nearby) only for what nobody in the filijala executes — except that „does not execute“ now never means „no room“. What an institution cannot do is not offered for CITO either: a closed day, a day without a quota, a switched-off or closed-for-the-day sampling type, age range, a missing route. Recommended: from=today, days=1–2.\nFILIJALA FIRST: filijalaPlan.reference is the patient's filijala (or the referring institution's when the patient has none). scope=home — every option is in it; scope=home_plus_nearby — the home filijala has options, but NO site in it can execute some item (home.uncovered = requirement keys nobody in the filijala executes: no sampling site does it in-house and none has a confirmed route to a laboratory that does, while someone in Serbia does) — for those items options from the nearest other filijale (nearbyFilijale) are ADDED as building blocks for the extra sampling order outside the home filijala (VMF): each carries filijalaScope=nearby or unknown_filijala, filijalaNote and supplementsFor (which of home.uncovered that site executes) and is TRIMMED TO THOSE ITEMS ONLY — whatever else the site could do goes to coverage.leftInFilijala (executed in the home filijala, not „bez mesta“), while coverage.covered, analysis, reserve, loincResolution and sampling.samplingTypes contain only the VMF items; a supplement is never complete, so it cannot be read as „everything at one place“ outside the filijala; home-filijala options always rank above them, the best supplement for every item survives limit, and samplingPlan (verdict, completeOptions, sitesCoveringAll) still describes the home filijala (split_referral · analysis), not the supplements. COMPOSED PLAN: samplingPlan.recommended = the sampling orders to create, in order — { rank, role, requirements }: role=primary is the home-filijala option that executes the most (everything the filijala can), role=vmf is one order outside the filijala per item of home.uncovered (needs the commission approval); verdict=one_site gives a single primary; empty when the registry cannot compose the split (no filijala, sampling-type split). Rule: the patient is never sent outside the filijala for what the filijala executes, and no ordered item someone in Serbia executes is dropped. ADMISSIBLE PLANS are exactly: a complete option on its own, or samplingPlan.recommended — a partial option (coverage.missing) is a building block of the composed plan and MUST NOT be offered as a plan by itself, not even as a „without commission“ alternative: a plan that leaves an ordered item without a place is not a plan; items nobody in Serbia executes are uncoveredServices — the referral has to change, no plan absorbs them. CLOCK AND WINDOW: today counts only while at least one declared window is still open (window end > now + 30 min, Serbian time) — a site whose windows already closed today is not offered today's date; sites without a window list (no template, capacity override) are not judged by the clock. A supplement MAY fall OUTSIDE the requested window: when no site in the home filijala executes an item and the supplement has no day inside the window (e.g. today's window closed), its first feasible day up to 7 days past `to` is offered and the option carries outsideWindow=true (filijalaNote names the day) — every order in recommended has its own site AND day; all other options (home, nearby without home options, no filijala) stay inside the window; scope=nearby — the home filijala has no option in the window, so options come from the nearest filijale (nearbyFilijale, nearest first), each carrying filijalaScope=nearby + filijalaNote; institutions not yet linked to the national registry (unknown filijala) appear only in the fallback tier as unknown_filijala; scope=none — no option; scope=unfiltered — no filijala known. home.sitesCoveringAll > 0 with scope=nearby means the home filijala could do it, just not in this window — widen the window.\nStops (with a patient filijala): 422 referring_institution_outside_patient_filijala when the referring institution is not in the patient's filijala (the message names both); 422 referring_institution_not_linked when the referring institution is not linked to the national registry (its filijala cannot be verified); 422 unknown_referring_institution for an unknown referring-institution code; 400 unknown_patient_filijala for a filijala that does not exist. POST with a JSON body { services, patient: { lat, lng, filijala }, referringInstitution, days, … } is equivalent to GET.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"services","in":"query","required":true,"description":"Comma-separated referral items: LOINC codes (the doctor's language, e.g. 2345-7) and/or NLU codes, freely mixed (service= with a single code is accepted too; loinc= is an alias for a pure LOINC list). A LOINC is translated at the input into its NLU variants — one LOINC = one requirement whose anyOf is the variant set (the \"OR\" for the LIS); a LOINC component (haemoglobin 718-7) ⇒ the panels containing it. \"OR\" OPERATOR: separate the alternatives of one requirement with | — \"any one of these will do\" (e.g. NLU-0242,NLU-0509|NLU-0510 = NLU-0242 AND (NLU-0509 OR NLU-0510)); a LOINC inside a group contributes the union of its variants; order is the doctor's preference. POST: [\"2345-7\", \"NLU-0242\", [\"NLU-0509\",\"NLU-0510\"]] or [{ \"anyOf\": [...] }]. Unknown / unmapped LOINC ⇒ translation[].reason + unknownServices, never a 400. Up to 50 requirements, up to 10 alternatives per group.","schema":{"type":"string"}},{"name":"patientAge","in":"query","required":true,"description":"PATIENT SECTION — REQUIRED: patient age in completed years (0–130, 0 = infant; POST: patient.age). An institution may limit a sampling type to the ages its staff is trained for (e.g. adults only); outside that range it is not proposed for services needing that sample — the reason is in coverage.ageRestricted (requirement, samplingType, ageRange, label). The age is carried into the reserve calls (patientAge). Missing ⇒ 400 required.","schema":{"type":"integer"}},{"name":"patientLat","in":"query","required":false,"description":"PATIENT SECTION — patient latitude (with patientLng; POST: patient.lat; legacy alias lat). When absent the referring institution is the reference point (originSource).","schema":{"type":"number"}},{"name":"patientLng","in":"query","required":false,"description":"Patient longitude (POST: patient.lng; legacy alias lng).","schema":{"type":"number"}},{"name":"patientFilijala","in":"query","required":false,"description":"RFZO id of the patient's filijala (1–32; POST: patient.filijala). Options are restricted to sampling sites in it; only when it has no option at all are the nearest other filijale offered, explicitly labelled (filijalaScope=nearby, filijalaNote). Without it the referring institution's filijala is the reference.","schema":{"type":"integer"}},{"name":"near","in":"query","required":false,"description":"Code of the REFERRING institution (alias referringInstitution; POST: referringInstitution) — its lab desk is the preferred sampling site and its coordinates the reference point when the patient has no geolocation. If it is in a different filijala than the patient the referral is stopped: 422 referring_institution_outside_patient_filijala.","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"First acceptable date (YYYY-MM-DD, default today).","schema":{"type":"string"}},{"name":"days","in":"query","required":false,"description":"Window length in days (1–60); alternative: to.","schema":{"type":"integer"}},{"name":"to","in":"query","required":false,"description":"Last acceptable date (inclusive); default from + 6.","schema":{"type":"string"}},{"name":"priority","in":"query","required":false,"description":"routine (default) | urgent = CITO referral (cito / hitno accepted too). CITO FLOW: capacity never excludes a sampling site — a spent quota (day, sampling type, analysis rule) is reported (sampling.overQuota, analysis[].overQuota) instead of ruling the date out, and the reserve calls are accepted over quota; today stays available after the windows ended (sampling.afterWindows — the urgent sample is taken outside routine hours); ranking is earliest day, then nearest site (score informational). Filijala first still applies: outside the patient's filijala only for what nobody in it executes. Capability is unchanged: a closed day, a switched-off / closed sampling type, age range and routes still exclude.","schema":{"type":"string"}},{"name":"cito","in":"query","required":false,"description":"CITO referral flag (cito=1; POST cito: true) — same as priority=urgent.","schema":{"type":"boolean"}},{"name":"mode","in":"query","required":false,"description":"any (default) | single (everything at one institution) | split (sampling + shipping over a route).","schema":{"type":"string"}},{"name":"maxKm","in":"query","required":false,"description":"Drop sampling sites farther than this from the origin.","schema":{"type":"number"}},{"name":"allowPartial","in":"query","required":false,"description":"Also return partial options (coverage.missing) — building blocks of the composed plan (samplingPlan.recommended), never standalone plans. Without it only options that are a whole plan by themselves (complete) are returned; the filijala plan (verdict, filijalaPlan) is identical either way, and a recommended that would rely on options not returned is empty.","schema":{"type":"boolean"}},{"name":"home","in":"query","required":false,"description":"HOME SAMPLING: only institutions that offer home visits, ranked on their separate home-visit quota and within their declared radius; lat/lng (or near) is the patient's home. Reserve calls carry mode: \"home\".","schema":{"type":"boolean"}},{"name":"limit","in":"query","required":false,"description":"Max plans (default 10, max 50).","schema":{"type":"integer"}},{"name":"sets","in":"query","required":false,"description":"ORDER SETS (NLS): NLS-0001 (current approved revision) or NLS-0001@3 (pinned revision — what an issued referral records), comma-separated; the same token may also appear in services. A set expands into its REQUIRED members, each an ordinary requirement (LOINC → NLU \"OR\"). POST: { \"orderSet\": \"NLS-0001\", \"revision\": 3, \"include\": [\"9830-1\"] | \"all\", \"exclude\": [\"2571-8\"] } inside services or in an orderSets list. Response: orderSets[] (revision used, every member with included/why, reason) and requirements[].fromOrderSets. A set may not be an alternative inside an OR group (400); unknown / unapproved / retired set ⇒ unknownServices + orderSets[].reason.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"services":[{"id":242,"code":"NLU-0242","name":"Glukoza u krvi/serumu/plazmi, POCT","category":"Biohemija"}],"requirements":[{"key":"NLU-0242","kind":"service","anyOf":["NLU-0242"],"unknown":[]}],"unknownServices":[],"uncoveredServices":[],"window":{"from":"2026-09-29","to":"2026-10-05","days":7},"origin":{"lat":44.3081,"lng":20.0116},"nearInstitution":{"code":"ZC-VALJEVO","name":"Zdravstveni centar Valjevo","city":"Valjevo","type":"laboratory","distanceKm":0},"priority":"routine","mode":"any","home":false,"candidatesConsidered":11,"returned":2,"samplingPlan":{"requiredTypes":[{"code":"TU-001","name":"Venska krv — serum/plazma","services":["NLU-0242"]}],"alternativeGroups":[],"sitesWithAllTypes":11,"sitesCoveringAll":9,"completeOptions":2,"verdict":"one_site","blocker":null,"recommended":[{"rank":1,"role":"primary","requirements":["NLU-0242"]}]},"options":[{"rank":1,"kind":"split","complete":true,"outsideWindow":false,"filijalaScope":"home","filijalaNote":null,"supplementsFor":[],"score":92,"scoreBreakdown":{"base":100,"distance":0,"wait":0,"handoff":-8,"turnaround":0,"samplingCapacity":0,"analysisCapacity":0,"partialCoverage":0,"secondSite":0},"sampling":{"institution":{"code":"ZC-VALJEVO","name":"Zdravstveni centar Valjevo","city":"Valjevo","distanceKm":0},"mode":"site","atOrigin":true,"date":"2026-09-29","state":"open","free":25,"overQuota":false,"afterWindows":false,"windows":[{"label":"Jutarnje uzorkovanje","startTime":"07:00:00","endTime":"10:00:00"}],"home":null},"analysis":[{"institution":{"code":"ELAB-374006","name":"Univerzitetski klinički centar Srbije","city":"Beograd","distanceKm":63.5},"inHouse":false,"services":["NLU-0242"],"date":"2026-09-30","transportDays":1,"transportWeekdays":[1,2,3,4,5],"cutoffTime":"10:30","tatHours":null,"state":"open","overQuota":false}],"coverage":{"covered":["NLU-0242"],"missing":[],"leftInFilijala":[],"notSampleable":[],"alternatives":[]},"resultEta":null,"alternativeDates":[{"date":"2026-09-30","kind":"split","complete":true}],"reserve":[{"method":"POST","path":"/api/registry/institutions/ZC-VALJEVO/capacity/reservations","body":{"referralRef":"{referralRef}","date":"2026-09-29","priority":"routine","samplings":1,"mode":"site","services":[]}},{"method":"POST","path":"/api/registry/institutions/ELAB-374006/capacity/reservations","body":{"referralRef":"{referralRef}","date":"2026-09-30","priority":"routine","samplings":0,"mode":"site","services":[{"code":"NLU-0242","quantity":1}]}}]}],"reserveNote":"Pozivi u reserve se izvršavaju redom sa istim referralRef; prvi rezerviše uzorkovanje, ostali analize u laboratorijama koje primaju uzorak."}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/loinc":{"get":{"operationId":"loinc-catalog","summary":"The doctor's catalog (orderable LOINC items)","description":"The referral system's analysis picker. LOINC IS THE DOCTOR'S LANGUAGE: the doctor picks a LOINC code — a result, never a method — and the registry translates it into the NLU services that produce it (variants). Several variants ⇒ the referral carries them all as \"OR\" (allowed) and the LIS picks method/analyser by its own policy. An item is a canonical LOINC code: method-specific and unit twins are folded into it (foldedAliases) and ordering any of them gives the same answer. ONLY items at least one live institution in Serbia performs AND whose LOINC is orderable and current are returned (ORDER_OBS Order/Both, not DEPRECATED; DISCOURAGED only when methodless and still orderable — LDH, urine sediment). \"PERFORMS\" = the service is executable through that institution, i.e. the pair sampling → analysis exists: the institution samples the variant's specimen type itself (has not switched it off under \"Vrste uzorkovanja\"), or a live sampling site that does ships the sample to it over a confirmed transport route. The filijala is not a criterion — the planner offers an institution without one in its fallback tier (unknown_filijala). A performer no sample can reach does not make an item orderable (excluded.performedNotExecutable) — so lab-options never answers \"nobody performs it\" for an item of this catalog. When no such institution performs the stand-alone service but a panel producing the same result is performed (e.g. reticulocytes ⇒ CBC with reticulocytes), the item is offered as a panel member (kind = component, variants = the panels) and returns as a service as soon as an institution the sample can reach confirms the stand-alone service. A result that is not ordered on its own (MCV, casts…) hits the panel that produces it (matchedOn.source = panel_member). EXCEPTION — DEAD ENDS: an item laboratories perform whose LOINC is not flagged orderable and that no listed panel produces is returned anyway, with warning = { reason, message } — the doctor may order it and the referral system shows warning.message next to the item (reason: observation_only | subset | discouraged | flags_unknown; DEPRECATED codes are never offered). Serbian names mirror the Šifarnik (LOINC 2.83); nameSrMissing=true ⇒ show nameEn.\n\nLIS CONTRACT: a referral item = { loinc, allowed: NLU[], component?: NLK }. The doctor picks a LOINC; only when the analysis institution is chosen does the code unfold into the NLU that institution performs — allowed = lab-options → options[].loincResolution[].allowed (institution in executedAt), plus component (NLK) for a panel member. allowed.length > 1 ⇒ the LIS picks method/analyser by its own policy and returns the EXECUTED NLU in the result. Without the planner: GET /api/registry/loinc/{loinc} → institutions[].performs gives the same set per institution. Order-set (NLS) members expand into the same kind of items.\nrelated = national services linked to the code too loosely to execute through it (equivalence narrower — a stimulation test, a diurnal profile; related). Ordering the LOINC NEVER runs them; when the doctor means them, offer them as separate items by NLU code.\nA variant set is INTERCHANGEABLE by definition: the same result from the same specimen class, differing in method/platform/unit only. Whatever is not interchangeable the editor keeps out of the set (as related) — the referral system never has to choose inside a set.\nThe same query also returns orderSets (first page, no kind) — the picker can offer an order set next to single items; sets are searched with the same words as items (šuk, jetra, štitasta…). Every item carries inOrderSets = the approved sets it belongs to (required = ticked by default, note = the doctor's note), so the picker can offer the whole \"Lipidni status\" next to \"Holesterol\". Item detail: GET /api/registry/loinc/{loinc}.\nWARNING (warning): an item with warning ≠ null is orderable ONLY because laboratories perform it and nothing else produces the result (a dead end). Show warning.message to the doctor on pick and do not block the pick; the referral carries the same { loinc, allowed } contract. As soon as a listed panel starts producing the result the item leaves the search and comes back as a panel_member — nothing changes on the client side. catalog.listedWithWarning = how many there are right now.\nCATALOG AND PLANNER AGREE: availability.institutions counts only institutions the service is executable through (they sample that specimen type themselves, or a confirmed route brings the sample from a site that does), so a catalog item always gets at least one lab-options option (before the time window and quotas). A performer no sample can reach is not counted — it is visible only in the detail (institutionsNotExecutable) and in the editor's review until sampling is switched on or a route is confirmed. An item whose stand-alone NLU dropped out this way while a panel carries it has kind = component and standaloneSetAside in the detail; the referral still carries { loinc, allowed } with the panels + component (NLK).","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"q","in":"query","required":false,"description":"Free text: every word must hit some name the system knows for the item — LOINC (sr/en/short), NLU/NLK name, L-code name, institutions' local LIS names, abbreviations (AST, KKS, A1AT), colloquial terms or a code (LOINC, NLU, NLK). Empty = the whole catalog alphabetically.","schema":{"type":"string"}},{"name":"patientFilijala","in":"query","required":false,"description":"RFZO id of the patient's filijala (alias filijala). Every item then carries availability.inFilijala + how (in_house | via_route) and a Serbian note that states plainly when the analysis is NOT reachable in that filijala and where it is performed.","schema":{"type":"integer"}},{"name":"kind","in":"query","required":false,"description":"service | component (component = a result inside a panel; the variants are then the panels containing it).","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Default 20, max 100.","schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"description":"Paging offset.","schema":{"type":"integer"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"total":1,"returned":1,"query":{"q":"šuk","patientFilijala":30,"kind":null,"limit":20,"offset":0,"expandedFrom":["šuk → glukoza"],"mode":"all"},"filijala":{"id":30,"naziv":"Filijala Beograd"},"catalog":{"builtAt":"2026-10-13T09:00:00.000Z","listed":466,"listedWithWarning":17,"performedInSerbia":549},"excluded":{"notOffered":178,"performedNotExecutable":0,"notOrderable":{"observation_only":69,"subset":0,"deprecated":0,"discouraged":0,"flags_unknown":14}},"items":[{"loinc":"14749-6","displayName":"Glukoza [mol/zapremina] u serumu ili plazmi","nameSr":"Glukoza [mol/zapremina] u serumu ili plazmi","nameEn":"Glucose [Moles/volume] in Serum or Plasma","nameSrMissing":false,"loincStatus":"ACTIVE","warning":null,"kind":"service","categories":["Biohemija"],"variants":[{"code":"NLU-0245","name":"Glukoza u serumu/plazmi, spektrofotometrija","method":"spektrofotometrija","relation":"broader","samplingType":{"id":1,"code":"TU-001","nameSr":"Venska krv — serum/plazma"}},{"code":"NLU-0242","name":"Glukoza u krvi/serumu/plazmi, POCT","method":"POCT","relation":"broader","samplingType":{"id":1,"code":"TU-001","nameSr":"Venska krv — serum/plazma"}}],"viaComponent":null,"alsoInPanels":[{"code":"NLU-0444","name":"OGTT","loinc":"20436-2","institutions":41,"inFilijala":true}],"foldedAliases":["2345-7","2339-0"],"samplingTypes":[{"id":1,"code":"TU-001","nameSr":"Venska krv — serum/plazma"}],"alsoKnownAs":["ŠUK","Glukoza","GLU"],"related":[],"availability":{"inSerbia":true,"institutions":131,"filijala":{"id":30,"naziv":"Filijala Beograd"},"inFilijala":true,"how":"in_house","filijalaInstitutions":24,"performedIn":[{"id":30,"naziv":"Filijala Beograd","institutions":24}],"note":"Radi se u kući u 24 ustanove u Filijali Beograd."},"matchedOn":[{"text":"ŠUK","source":"abbreviation","code":"NLU-0245"}],"relevance":96,"inOrderSets":[{"code":"NLS-0008","ref":"NLS-0008@1","name":"Osnovni laboratorijski pregled","required":true,"note":null},{"code":"NLS-0009","ref":"NLS-0009@1","name":"Praćenje dijabetesa","required":true,"note":null}]}],"orderSets":[{"code":"NLS-0009","ref":"NLS-0009@1","name":"Praćenje dijabetesa","clinicalContext":"Dijabetes melitus tip 1 i 2 — kontrola glikemije i skrining nefropatije","matchedOn":"name","detail":"/api/registry/order-sets/NLS-0009@1"}],"note":"Stavka = LOINC šifra koju lekar bira; variants su NLU koje je izvode …"}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/loinc/{loinc}":{"get":{"operationId":"loinc-detail","summary":"One LOINC item (picker detail)","description":"Everything about one catalog item once the doctor picks it: variants, panels, the institutions performing it (optionally only in the patient's filijala, with performs = the variants that very institution runs — the \"OR\" its LIS would receive), related services, the order sets it belongs to (inOrderSets, with required/note) and links to preparation/guidance, the planner, diagnoses and those sets. An alias resolves to its canonical item (requested ≠ loinc). institutions holds only institutions the service is executable through; institutionsNotExecutable names performers no sample can reach (never offered) and standaloneSetAside the stand-alone NLU variants no such institution performs while the item is ordered through the panels in variants. An item the search does NOT list (nobody performs it — or only institutions no sample can reach do — or the LOINC is not orderable) is still returned here with orderable=false, the reason (notListedReason) and orderVia = the panels to order instead. A dead end (performed, code not orderable, no panel) has orderable=true and warning { reason, message } — the message is repeated in orderableNote.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"loinc","in":"path","required":true,"description":"LOINC code (form 12345-6); alias or canonical.","schema":{"type":"string"}},{"name":"patientFilijala","in":"query","required":false,"description":"RFZO id of the patient's filijala (alias filijala) — institutions narrows to it (institutionsScope = filijala), availability gains inFilijala/how/note.","schema":{"type":"integer"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":"{\n  \"requested\": \"2345-7\", \"loinc\": \"14749-6\", \"displayName\": \"Glukoza [mol/zapremina] u serumu ili plazmi\", \"kind\": \"service\",\n  \"variants\": [{ \"code\": \"NLU-0245\", \"method\": \"spektrofotometrija\", \"relation\": \"broader\" }, { \"code\": \"NLU-0242\", \"method\": \"POCT\", \"relation\": \"broader\" }],\n  \"related\": [], \"foldedAliases\": [\"2345-7\", \"2339-0\"],\n  \"orderable\": true, \"listed\": true, \"notListedReason\": null, \"warning\": null, \"orderableNote\": null, \"orderVia\": [],\n  \"orderObs\": \"Both\", \"loincStatus\": \"ACTIVE\",\n  \"inOrderSets\": [\n    { \"code\": \"NLS-0008\", \"ref\": \"NLS-0008@1\", \"name\": \"Osnovni laboratorijski pregled\", \"required\": true, \"note\": null },\n    { \"code\": \"NLS-0009\", \"ref\": \"NLS-0009@1\", \"name\": \"Praćenje dijabetesa\", \"required\": true, \"note\": null }\n  ],\n  \"institutions\": [{ \"code\": \"ZC-VALJEVO\", \"name\": \"Zdravstveni centar Valjevo\", \"city\": \"Valjevo\", \"filijala\": { \"id\": 9, \"naziv\": \"Filijala Valjevo\" }, \"performs\": [\"NLU-0245\"] }],\n  \"institutionsScope\": \"all\",\n  \"institutionsWithoutFilijala\": [], \"standaloneSetAside\": [],\n  \"links\": { \"guidance\": \"/api/registry/services/14749-6/guidance\", \"labOptions\": \"/api/registry/lab-options?services=14749-6\", \"diagnosesValidate\": \"/api/registry/diagnoses/validate\", \"orderSets\": [\"/api/registry/order-sets/NLS-0008@1\", \"/api/registry/order-sets/NLS-0009@1\"] },\n  \"descriptors\": [{ \"text\": \"ŠUK\", \"source\": \"abbreviation\", \"code\": \"NLU-0245\" }]\n}\n// 404 { \"error\": \"…\", \"reason\": \"loinc_unmapped\", \"loinc\": \"1234-5\", \"nameEn\": \"…\" }  — poznat LOINC bez nacionalne usluge; loinc_unknown — nepoznata šifra"}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/order-sets":{"get":{"operationId":"order-sets","summary":"Order sets for the doctor (approved NLS)","description":"Approved order sets (\"Lipid status\", \"Liver tests\"…) for the referral system's picker. A set is a MACRO: picking it adds its members to the referral — each member is an ordinary item, a LOINC code (the doctor's language; the laboratory picks the method from anyOf) or, where no LOINC exists, an NLU. Required members are ticked by default, optional ones offered unticked with their note. The referral records ref (NLS-0001@3) next to the expanded items for its audit trail; a set is NOT a billing unit. Only RSK-approved revisions are returned.\n\nThe referral item for the LIS stays { loinc, allowed: NLU[] } — a set only picks items; a member's anyOf is that allowed set.\nMembers are resolved against today's registry (a revision stores codes only): a corrected LOINC mapping applies without a new revision; orderable=false + warnings when nobody can execute the member right now.\nGET /api/registry/loinc?q=… also returns orderSets (first page) in the same response — the picker can offer a set next to single analyses.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"q","in":"query","required":false,"description":"Search over code, name, description and clinical context; a member name also matches (\"holesterol\" → Lipid status, matchedOn: \"member\"). Words are read as in the item catalog: the same colloquial dictionary (\"šuk\" → glukoza, \"jetra\" → AST/ALT/bilirubin, \"štitasta\" → TSH; expandedFrom in the response), Serbian endings are tolerated (\"štitasta\" finds \"štitaste\"), đ may be typed as dj. Empty = all.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Default 20, max 100.","schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"description":"Paging offset.","schema":{"type":"integer"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"total":1,"returned":1,"query":"masnoće","expandedFrom":["masnoce → holesterol, cholesterol, triglicerid, lipid"],"items":[{"code":"NLS-0001","revision":1,"ref":"NLS-0001@1","currentRevision":1,"isCurrent":true,"status":"active","name":"Lipidni status","clinicalContext":"Procena kardiovaskularnog rizika, praćenje hipolipemijske terapije","loincPanel":{"loinc":"24331-1","nameSr":"Lipidni panel 1996 - serum ili plazma"},"members":[{"position":1,"kind":"loinc","code":"2093-3","required":true,"note":null,"displayName":"Holesterol [mol/zapremina] u serumu ili plazmi","canonical":"14647-2","loincKind":"service","anyOf":["NLU-0280","NLU-0282"],"offeredBy":120,"orderable":true,"warnings":[]},{"position":5,"kind":"loinc","code":"9830-1","required":false,"note":"Indeks ateroskleroze","anyOf":["NLU-0283","NLU-0611"],"orderable":true}],"matchedOn":"name"}]}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/order-sets/{code}":{"get":{"operationId":"order-set-detail","summary":"One order-set revision","description":"An approved set revision: NLS-0001 = current, NLS-0001@2 (or ?revision=2) = pinned — what an issued referral recorded. A retired set stays readable (status: retired) so old referrals resolve; lab-options refuses new orders of a retired set (order_set_retired).","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"code","in":"path","required":true,"description":"NLS-0001 or NLS-0001@2.","schema":{"type":"string"}},{"name":"revision","in":"query","required":false,"description":"Alternative to @revision in the path.","schema":{"type":"integer"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":"{\n  \"code\": \"NLS-0001\", \"revision\": 1, \"ref\": \"NLS-0001@1\", \"currentRevision\": 1, \"isCurrent\": true, \"status\": \"active\",\n  \"name\": \"Lipidni status\", \"members\": [ … ], \"revisions\": [{ \"revision\": 1, \"approvedAt\": \"2026-10-06T10:12:00Z\" }]\n}\n// 404 { \"error\": \"NLS-0099: nepoznat set analiza\", \"reason\": \"order_set_unknown\" }  — takođe order_set_not_published, order_set_revision_unknown"}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/institutions/{code}/sampling-types":{"get":{"operationId":"institution-sampling-types","summary":"Sampling types the institution performs","description":"The institution's capability as a SAMPLING SITE: for every national sampling type (TU) whether that sample is taken at the institution (performed) and the admin's note visible to referral systems (e.g. 'weekdays until 10:00 only'). ageRange {minYears,maxYears,allAges,label} = patient ages the staff is trained for (null = no bound; outside it the planner skips the institution for that sample, a reservation with patientAge is refused with sampling_type_age_restricted). performed=false means the planner (lab-options) will not propose the institution for a service needing that sample, and POST …/capacity/reservations refuses it with sampling_type_unavailable. declared=false = the institution never decided; treated as performed. WHICH TUBE the sample goes into is GET /api/registry/sampling-plan.\n\nTypes the institution never declared (declared=false) are returned with performed=true — behaviour is unchanged from before declarations existed.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"code","in":"path","required":true,"description":"Laboratory institution code (must be live).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"institution":{"code":"ELAB-374006","name":"Univerzitetski klinički centar Srbije"},"total":14,"performed":13,"notPerformed":["TU-007"],"samplingTypes":[{"code":"TU-001","nameSr":"Venska krv — serum/plazma","nameEn":"Venous blood — serum/plasma","specimenClass":"Serum/plazma","collectionMethod":"Venepunkcija","performed":true,"declared":true,"note":null,"offeredServices":212,"updatedAt":"2026-09-29T08:12:44.000Z"},{"code":"TU-007","nameSr":"Likvor","nameEn":"Cerebrospinal fluid","specimenClass":"Likvor","collectionMethod":"Lumbalna punkcija","performed":false,"declared":true,"note":"Uzorak stiže sa neurologije partnerske ustanove","offeredServices":6,"updatedAt":"2026-09-29T08:15:02.000Z"}]}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/institutions/{code}/capacity":{"get":{"operationId":"lab-capacity","summary":"Laboratory day capacity","description":"Day-by-day intake picture of a laboratory for referral systems: sampling capacity, usage, status (open | limited | full | closed), the sampling windows of the day, the urgent reserve and the analysis limits per category or NLU code with their usage. Referrers pick a date BEFORE posting a reservation — a full day is refused by POST …/capacity/reservations when the institution's policy is hard-stop. Range defaults to today … today + booking horizon, capped at 60 days.\n\nAn institution key (eup_) may read and reserve ONLY its own capacity (403 otherwise); a system key (eur_) may act on any institution — reservations for referrals (CEU) are sent by the Centralni eUput sistem under its main key.\ndays[] is the ON-SITE intake quota. When the institution offers home sampling, homeSampling carries the offer (conditions, radius in km) and homeDays[] the SEPARATE daily home-visit quota for the same range — reserve it with mode: \"home\". An institution without the offer returns homeSampling.offered: false and an empty homeDays.\ndays[].samplingTypes[] = sampling types (TU) the institution caps SEPARATELY that day (sub-quota): status open | limited | full | closed (closed = type unavailable that day, e.g. equipment service), capacity/used/free as for the day. A referral needing such a type fits only when both the day and the sub-quota have room; types absent from the array are bounded by the day total only. Types the institution never performs are on GET …/sampling-types.\nA non-live institution returns 409 (business-rule); errors are FHIR OperationOutcome resources.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"code","in":"path","required":true,"description":"Laboratory institution code (must be live).","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"First day (YYYY-MM-DD, default today).","schema":{"type":"string"}},{"name":"days","in":"query","required":false,"description":"Number of days (1–60); alternative: to.","schema":{"type":"integer"}},{"name":"to","in":"query","required":false,"description":"Last day (inclusive); default from + horizon − 1, range ≤ 60 days.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"institution":{"code":"ZC-VALJEVO","name":"Zdravstveni centar Valjevo"},"policy":{"softThresholdPct":80,"overbookPct":0,"hardStop":true,"horizonDays":30,"lastBookableDate":"2026-10-29"},"range":{"from":"2026-10-05","to":"2026-10-06"},"homeSampling":{"offered":true,"note":"Samo nepokretni pacijenti, uz uput; zakazivanje dan ranije.","radiusKm":25},"homeDays":[{"date":"2026-10-05","mode":"home","status":"open","capacity":8,"ceiling":8,"used":2,"free":6,"freeRoutine":5,"urgentReserve":1,"pct":25,"windows":[{"label":"Kućne posete — jutarnja tura","start":"07:00:00","end":"11:00:00","capacity":8}],"exception":null}],"days":[{"date":"2026-10-05","mode":"site","status":"open","capacity":30,"ceiling":30,"used":0,"free":30,"freeRoutine":25,"urgentReserve":5,"pct":0,"windows":[{"label":"Jutarnje uzorkovanje","start":"07:00:00","end":"10:00:00","capacity":30}],"exception":null,"samplingTypes":[{"code":"TU-007","name":"Bris grla","status":"open","capacity":10,"ceiling":10,"used":4,"free":6,"freeRoutine":6,"urgentReserve":0,"windows":[{"label":"Bris grla","start":"07:00:00","end":"09:00:00","capacity":10}],"exception":null},{"code":"TU-012","name":"Spirometrija","status":"closed","capacity":0,"ceiling":0,"used":0,"free":0,"freeRoutine":0,"urgentReserve":0,"windows":[],"exception":{"kind":"closed","reason":"Servis opreme"}}],"analyses":[{"scope":"category","category":"Mikrobiologija","service":null,"capacity":40,"used":12,"tatHours":72},{"scope":"service","category":null,"service":"NLU-0509","capacity":20,"used":3,"tatHours":null}]}]}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/institutions/{code}/capacity/reservations":{"post":{"operationId":"lab-capacity-reserve","summary":"Reserve capacity for a referral","description":"Reserves intake for ONE referral on ONE day: patient visits for sampling (samplings) and analyses per NLU code (services). referralRef is an idempotency key within the institution — a repeated call with the same referralRef returns the existing reservation with 200 (created: false) instead of a duplicate. 201 when reserved, with the day picture after the reservation. 409 with refusal when the day is closed, full, beyond the horizon or an analysis limit is hit; alternatives lists the next dates that fit and redirect (when the policy allows) nearby laboratories with room that day. samplings: 0 is used when the sample arrives from another institution (split plan from /lab-options).\n\nRefusal (409): { resourceType: \"OperationOutcome\", issue: [{ code: \"business-rule\", diagnostics }], refusal: { code, detail, day, alternatives: [{ date, status, free }], redirect: [{ code, name, city, km, status, free }] } }.\nrefusal.code: closed | full | no_capacity | analysis_full | sampling_type_unavailable | sampling_type_full | past | beyond_horizon | unknown_service | unknown_sampling_type | home_sampling_unavailable. alternatives = up to 5 next dates (within the horizon) on which the SAME request would fit — on the SAME quota (site or home) and for the same sampling types; redirect = up to 5 nearest live laboratories with room that day on the same quota (for home: only institutions offering home visits whose radius covers this institution), only when the institution's policy allows it (otherwise an empty array).\nSampling-type sub-quotas: the day may be open and the reservation still refused — sampling_type_unavailable when the institution does not perform that type or it is unavailable that day (detail.samplingType {code, name}, detail.reason), sampling_type_full when the type's daily sub-quota is spent (detail.capacity/used/free/requested). Types are derived from services or given in samplingTypes.\nHome sampling: mode: \"home\" + samplings ≥ 1 drains the home-visit quota; day in the response pictures that quota (day.mode: \"home\"). Analyses (services) are reserved exactly as for on-site intake.\nCITO (priority: \"urgent\"): full, sampling_type_full and analysis_full are NOT returned — the reservation is written over quota (201) and reservation.overQuota lists the overrun; day after the write shows used > ceiling. These are the reserve calls /lab-options returns for a CITO referral (sampling.overQuota / analysis[].overQuota on the option announce the overrun in advance).","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"code","in":"path","required":true,"description":"Laboratory institution code.","schema":{"type":"string"}}],"responses":{"200":{"description":"Already exists for this referralRef (idempotent replay, created: false)","content":{"application/json":{"example":{"reservation":{"referralRef":"UPUT-2026-000123","date":"2026-10-05","mode":"site","bookingIds":[4812,4813],"created":true,"overQuota":null},"day":{"date":"2026-10-05","mode":"site","status":"open","capacity":30,"ceiling":30,"used":1,"free":29,"freeRoutine":24,"pct":3}}}}},"201":{"description":"Created","content":{"application/json":{"example":{"reservation":{"referralRef":"UPUT-2026-000123","date":"2026-10-05","mode":"site","bookingIds":[4812,4813],"created":true,"overQuota":null},"day":{"date":"2026-10-05","mode":"site","status":"open","capacity":30,"ceiling":30,"used":1,"free":29,"freeRoutine":24,"pct":3}}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"},"409":{"description":"Refused by a business rule (FHIR OperationOutcome with refusal details)"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["referralRef","date"],"properties":{"referralRef":{"description":"Referral number — idempotency key (up to 80 chars)."},"date":{"description":"Intake day (YYYY-MM-DD)."},"priority":{"description":"routine (default) | urgent = CITO (cito / hitno accepted too). CITO is never refused on capacity: the reservation is written OVER quota and reservation.overQuota says what was exceeded ({ sampling: { free, requested } | null, samplingType: { code, name, free, requested } | null, analysis: [{ rule, free, requested }] }; null when nothing). A closed day, a day without a quota, an unavailable sampling type, age range and the horizon refuse CITO too."},"samplings":{"description":"Patient visits for sampling (0–50, default 1; 0 = analyses only)."},"mode":{"description":"site (default) | home — which sampling quota the samplings drain: on-site places or the SEPARATE home-visit quota (home sampling). home at an institution that does not offer it returns 409 home_sampling_unavailable."},"services":{"description":"Array of { code: NLU code, quantity? (1–50, default 1) }, up to 200 items. Required when samplings is 0."},"samplingTypes":{"description":"Array of TU codes (up to 20) — sampling types the visit needs. Derived from services by default (each NLU service's sampling type); given values REPLACE the derived set. Checked only for mode: site and samplings ≥ 1."},"note":{"description":"Note (up to 500 chars)."}}}}}}}},"/api/registry/institutions/{code}/capacity/reservations/{ref}":{"get":{"operationId":"lab-capacity-reservation","summary":"Reservation status by referral number","description":"Every ledger item of one referral at the institution: sampling (kind=sampling) and analyses (kind=analysis, with NLU code or category), date, priority and status (reserved | released). The summary status is reserved while at least one item is active.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"code","in":"path","required":true,"description":"Laboratory institution code.","schema":{"type":"string"}},{"name":"ref","in":"path","required":true,"description":"The referralRef of the reservation.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"referralRef":"UPUT-2026-000123","date":"2026-10-05","status":"reserved","items":[{"id":4812,"date":"2026-10-05","kind":"sampling","quantity":1,"priority":"routine","status":"reserved","category":null,"serviceCode":null,"createdAt":"2026-09-29T09:07:24.182Z","releasedAt":null},{"id":4813,"date":"2026-10-05","kind":"analysis","quantity":1,"priority":"routine","status":"reserved","category":"Biohemija","serviceCode":"NLU-0022","createdAt":"2026-09-29T09:07:24.182Z","releasedAt":null}]}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}},"delete":{"operationId":"lab-capacity-release","summary":"Release a reservation","description":"Releases every active item of the reservation when the referral is cancelled or redirected — capacity returns to the day picture immediately. Idempotent: released is the number of items released, a repeated call returns 200 with released: 0.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"code","in":"path","required":true,"description":"Laboratory institution code.","schema":{"type":"string"}},{"name":"ref","in":"path","required":true,"description":"The referralRef of the reservation.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"referralRef":"UPUT-2026-000123","released":2}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/rad/institutions/{code}/slots":{"get":{"operationId":"rad-slots","summary":"Free radiology slots per device","description":"Free slots of a radiology institution (NRRU) for one service (service = NRU code) OR a modality (CT, MR, RTG, UZ, MG…) — one of them is required. Returns the devices (resources) that perform the request and slots with slotId, date, time, length in slots (span) and device. Urgent priority also sees slots reserved for urgent cases (urgentOnly). hint explains an empty result: no_resource (no active device performs the modality) or no_slot (device exists, no free slot) — then the referral goes to POST …/slot-issues.\n\nRadiology endpoints accept ONLY the BIS/ZIS system key (eur_) — an institution key (eup_) is a laboratory credential and returns 403.","security":[{"generalApiKey":[]}],"parameters":[{"name":"code","in":"path","required":true,"description":"Radiology institution code (RU-XXXX).","schema":{"type":"string"}},{"name":"service","in":"query","required":false,"description":"NRU radiology service code (determines modality and duration).","schema":{"type":"string"}},{"name":"modality","in":"query","required":false,"description":"Modality (CT, MR, RTG, UZ, MG…) when no specific service is requested.","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"First day (YYYY-MM-DD, default today; must not be in the past).","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"Last day (inclusive; default from + 27, range ≤ 90 days).","schema":{"type":"string"}},{"name":"priority","in":"query","required":false,"description":"routine (default) | urgent.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Max slots (default 50, max 200).","schema":{"type":"integer"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"institution":{"code":"RU-001","name":"Klinički centar Srbije — Radiologija"},"query":{"service":null,"modality":"MR","from":"2026-09-29","to":"2026-10-26","priority":"routine","limit":50},"resources":[{"code":"MR-1","name":"MR 1.5T","modality":"MR","slotMinutes":20}],"slots":[{"slotId":26,"date":"2026-09-29","start":"07:20:00","end":"07:40:00","span":1,"resource":{"code":"MR-1","name":"MR 1.5T","modality":"MR"},"urgentOnly":false}],"hint":null}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/rad/institutions/{code}/bookings":{"post":{"operationId":"rad-book","summary":"Book a radiology slot","description":"Books a slot from /slots for one referral. referralRef is idempotent — a referral with an active booking gets the existing one with 200 (created: false) instead of a double booking. 201 when booked. 409 OperationOutcome when the slot was filled meanwhile (full), is blocked (blocked), reserved for urgent cases (urgent_only) or the service needs more consecutive slots than are free (no_span) — the caller picks another slot from /slots.","security":[{"generalApiKey":[]}],"parameters":[{"name":"code","in":"path","required":true,"description":"Radiology institution code.","schema":{"type":"string"}}],"responses":{"200":{"description":"Already exists for this referralRef (idempotent replay, created: false)","content":{"application/json":{"example":{"booking":{"bookingId":3,"slotId":26,"referralRef":"UPUT-2026-000124","created":true,"date":"2026-09-29","start":"07:20:00","end":"07:40:00","span":1,"resource":"MR-1"}}}}},"201":{"description":"Created","content":{"application/json":{"example":{"booking":{"bookingId":3,"slotId":26,"referralRef":"UPUT-2026-000124","created":true,"date":"2026-09-29","start":"07:20:00","end":"07:40:00","span":1,"resource":"MR-1"}}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"},"409":{"description":"Refused by a business rule (FHIR OperationOutcome with refusal details)"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slotId","referralRef"],"properties":{"slotId":{"description":"slotId from /slots."},"referralRef":{"description":"Referral number — idempotency key (up to 80 chars)."},"service":{"description":"NRU service code (must be active); determines duration (span)."},"priority":{"description":"routine (default) | urgent."},"note":{"description":"Note (up to 500 chars)."}}}}}}}},"/api/registry/rad/institutions/{code}/bookings/{ref}":{"get":{"operationId":"rad-booking","summary":"Radiology booking status by referral number","description":"The referral's active booking (active, or null when none) and the full history — booked and cancelled appointments with device, service and times.","security":[{"generalApiKey":[]}],"parameters":[{"name":"code","in":"path","required":true,"description":"Radiology institution code.","schema":{"type":"string"}},{"name":"ref","in":"path","required":true,"description":"The referralRef of the booking.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"referralRef":"UPUT-2026-000124","active":{"bookingId":3,"slotId":26,"status":"booked","priority":"routine","span":1,"date":"2026-09-29","start":"07:20:00","end":"07:40:00","resource":"MR-1","resourceName":"MR 1.5T","service":"NRU-0012","createdAt":"2026-09-29T09:07:27.987Z","cancelledAt":null},"history":[{"bookingId":3,"status":"booked","date":"2026-09-29","start":"07:20:00","end":"07:40:00","resource":"MR-1"}]}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}},"delete":{"operationId":"rad-cancel","summary":"Cancel a radiology booking","description":"Cancels the referral's active booking — the seat returns to /slots immediately. Idempotent: with no active booking it returns 200 with cancelled: false.","security":[{"generalApiKey":[]}],"parameters":[{"name":"code","in":"path","required":true,"description":"Radiology institution code.","schema":{"type":"string"}},{"name":"ref","in":"path","required":true,"description":"The referralRef of the booking.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"referralRef":"UPUT-2026-000124","cancelled":true,"bookingId":3}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/rad/institutions/{code}/slot-issues":{"post":{"operationId":"rad-slot-issue","summary":"Waiting list when no slot fits","description":"When /slots returns no fitting slot, the referral is put on the institution's waiting list. reason is derived automatically: no_resource (no active device performs the service's modality) or no_slot. Idempotent per referralRef while the issue is open (created: false). The radiology institution resolves the item from its portal (Termini → Lista čekanja) and books when a slot frees up.","security":[{"generalApiKey":[]}],"parameters":[{"name":"code","in":"path","required":true,"description":"Radiology institution code.","schema":{"type":"string"}}],"responses":{"200":{"description":"Already exists for this referralRef (idempotent replay, created: false)","content":{"application/json":{"example":{"issue":{"id":2,"referralRef":"UPUT-2026-000125","status":"open","reason":"no_slot","created":true}}}}},"201":{"description":"Created","content":{"application/json":{"example":{"issue":{"id":2,"referralRef":"UPUT-2026-000125","status":"open","reason":"no_slot","created":true}}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"},"409":{"description":"Refused by a business rule (FHIR OperationOutcome with refusal details)"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["referralRef"],"properties":{"referralRef":{"description":"Referral number (up to 80 chars)."},"service":{"description":"NRU service code — determines the modality for reason."},"priority":{"description":"routine (default) | urgent."},"requestedFrom":{"description":"Requested period from (YYYY-MM-DD)."},"requestedTo":{"description":"Requested period to (YYYY-MM-DD, ≥ requestedFrom)."},"note":{"description":"Note (up to 500 chars)."}}}}}}}},"/api/registry/resolve":{"get":{"operationId":"resolve","summary":"Reverse lookup of a local code (BIS/LIS)","description":"The calling institution submits a code and gets the fully linked national record. Three forms: ?code= (eLab record code), ?elab= (eLab service id), ?lis= (TRUE local LIS code from the uploaded catalog). The institution comes from auth headers — it can only resolve its own catalog. The match field discriminates: service (directly mapped to an NLU), components (mapped only to NLK analytes — lists panels containing them), none (no mapping).","security":[{"apiKey":[],"institutionId":[]}],"parameters":[{"name":"code","in":"query","required":false,"description":"eLab record code (default form).","schema":{"type":"string"}},{"name":"elab","in":"query","required":false,"description":"eLab service id.","schema":{"type":"string"}},{"name":"lis","in":"query","required":false,"description":"TRUE local LIS code.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"match":"service","by":"elabCode","service":{"code":"NLU-0022","displaySr":"Glukoza","loinc":[],"lcodes":[],"components":[]}}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/translate":{"get":{"operationId":"translate","summary":"Code translation between systems (FHIR $translate)","description":"FHIR ConceptMap $translate-style: translates a code from a source system to all matching codes in the target system via the national concept hub. Systems: rfzo-l, loinc, concept (an NLU code directly). Response is a FHIR Parameters resource.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"system","in":"query","required":true,"description":"Source system: rfzo-l | loinc | concept.","schema":{"type":"string"}},{"name":"code","in":"query","required":true,"description":"Code in the source system.","schema":{"type":"string"}},{"name":"target","in":"query","required":true,"description":"Target system: rfzo-l | loinc | concept.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"resourceType":"Parameters","parameter":[{"name":"result","valueBoolean":true},{"name":"match","part":[{"name":"concept","valueCoding":{"system":"loinc","code":"2345-7","display":"Glucose [Moles/volume] in Serum or Plasma"}}]}]}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/changelog":{"get":{"operationId":"changelog","summary":"Release changelog (delta sync)","description":"What changed between the previous published release and the requested one — supports delta-syncing client caches. Without a parameter, returns the latest published release.","security":[{"apiKey":[],"institutionId":[]},{"generalApiKey":[]}],"parameters":[{"name":"version","in":"query","required":false,"description":"Release version (e.g. 2026.1). Default: latest.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"version":"2026.1","publishedAt":"2026-07-01T10:00:00Z","previousVersion":"2025.2","changes":{"added":[],"changed":[],"retired":[]}}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/export/manifest":{"get":{"operationId":"export-manifest","summary":"Release manifest (daily check)","description":"PUBLIC, no key. Small response with version, publish date and filenames of the latest published release. Recommended daily flow for offline integrations: call the manifest once a day, compare publishedAt with your last imported edition — if newer, download /api/registry/export. Filenames embed the publish date, so a new edition is detectable from the name alone.","security":[],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"version":"2026.1","publishedAt":"2026-07-29T15:38:12.087Z","publishDate":"2026-07-29","conceptCount":677,"exportUrl":"/api/registry/export","formats":["json","xml","csv"],"filenames":{"public":{"json":"euput-registar-2026.1-2026-07-29-javni.json"},"elab":{"json":"euput-registar-2026.1-2026-07-29-elab.json"},"lab":{"json":"euput-registar-2026.1-2026-07-29-lab-{USTANOVA}.json"}}}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}},"/api/registry/export":{"get":{"operationId":"bulk-export","summary":"Bulk release export (offline import)","description":"The complete nomenclature of the latest published release in one file — for institutions preferring daily offline imports over the live API. Content scope is decided AUTOMATICALLY from credentials: no key → public scope (clean NLU/NLK nomenclature with LOINC/L-codes/sampling types, no internal IDs); x-api-key + x-institution-id → lab scope (+ that institution's OWN local LIS mappings only); x-elab-api-key → elab scope (+ all institutions' eLab mappings). A wrong key returns 401 — never silently downgraded. The Content-Disposition filename embeds version and publish date.\n\nThe response carries X-Registry-Version and X-Registry-Published-At headers so clients can record the import without parsing the body.\nFilename: euput-registar-{version}-{YYYY-MM-DD}-{javni|elab|lab-INSTITUTION}.{json|xml|csv}.\nSame content per version: /api/releases/{version}/export (same access scopes).","security":[{},{"apiKey":[],"institutionId":[]},{"elabApiKey":[]}],"parameters":[{"name":"format","in":"query","required":false,"description":"json (default), xml or csv (UTF-8 BOM, \";\" separator).","schema":{"type":"string"}},{"name":"version","in":"query","required":false,"description":"A specific published release (default: latest).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"resourceType":"CodeSystem","version":"2026.1","date":"2026-07-29T15:38:12.087Z","scope":{"kind":"public"},"count":677,"concept":[{"code":"NLU-0022","display":"Glukoza","loinc":["2345-7"],"rfzoLCodes":["L000414"],"property":[{"code":"samplingType","valueString":"TU-001"}]}],"component":[{"code":"NLK-0039","display":"Kalcijum","loinc":"17861-6"}]}}}},"401":{"description":"Missing or invalid API key headers"},"404":{"description":"Unknown code, institution or release"}}}}}}