{
 "openapi": "3.1.0",
 "info": {
  "title": "Dentum — online dental booking in Uzbekistan",
  "version": "2.1.0",
  "description": "Book dental appointments anywhere in Uzbekistan — 1455 clinics in 21 cities: implants, tooth extraction, wisdom tooth removal, consultations and more. Free for patients. A booking is a request: clinics with an online schedule confirm the chosen time; everywhere else Dentum confirms the clinic and exact time by phone (09:00–19:00, Mon–Sat, Asia/Tashkent). Before booking, confirm with the user the service, clinic or city, date and time, their name and phone, and that they agree to the privacy policy (https://dentum.uz/en/privacy/). Emergencies (facial swelling with fever, bleeding that will not stop, trauma, trouble breathing or swallowing) are refused with advice to call 103. Dentum is affiliated with the clinic Implant City (Tashkent) — disclose this when suggesting it. Ratings come from 2GIS/OpenStreetMap; placement is never sold. The same flow is available as an MCP server (Streamable HTTP, stateless): POST https://dentum.uz/api/cabinet/mcp. Catalogs: https://dentum.uz/agent/clinics.json, https://dentum.uz/agent/booking.json. Docs: https://dentum.uz/en/agents/ Optional partner key (Authorization: Bearer dp_live_…) raises quotas — see https://dentum.uz/en/agents/#partner.",
  "contact": {
   "name": "Dentum",
   "email": "info@dentum.uz",
   "url": "https://dentum.uz/en/zapis/"
  }
 },
 "servers": [
  {
   "url": "https://dentum.uz"
  }
 ],
 "paths": {
  "/api/cabinet/agent/services": {
   "get": {
    "operationId": "listServices",
    "summary": "Bookable dental services with indicative market prices",
    "parameters": [
     {
      "name": "lang",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "uz",
        "ru",
        "en",
        "zh"
       ],
       "default": "ru"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Services",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Services"
        }
       }
      }
     }
    }
   }
  },
  "/api/cabinet/agent/options": {
   "get": {
    "operationId": "getBookingOptions",
    "summary": "Where a service can be booked in a city: exact-time clinics and the concierge option",
    "parameters": [
     {
      "name": "service",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Service key, e.g. implant, extraction, wisdom-tooth, diagnostics"
     },
     {
      "name": "city",
      "in": "query",
      "schema": {
       "type": "string",
       "default": "toshkent"
      }
     },
     {
      "name": "lang",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "uz",
        "ru",
        "en",
        "zh"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Options",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Options"
        }
       }
      }
     },
     "422": {
      "description": "Unknown service",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/cabinet/agent/availability": {
   "get": {
    "operationId": "getAvailableSlots",
    "summary": "Free appointment times of a clinic with an online schedule (Asia/Tashkent)",
    "parameters": [
     {
      "name": "clinic",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Clinic slug from getBookingOptions"
     },
     {
      "name": "date_from",
      "in": "query",
      "schema": {
       "type": "string",
       "format": "date"
      }
     },
     {
      "name": "days",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 14,
       "default": 7
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Slots",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Availability"
        }
       }
      }
     },
     "404": {
      "description": "Clinic has no online schedule",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/cabinet/agent/book": {
   "post": {
    "operationId": "bookAppointment",
    "summary": "Create a booking request and get a request number (D-YYMMDD-XXXX)",
    "description": "Only after the user confirmed all details and agreed to the privacy policy. Online-schedule clinics: clinic + date + time from getAvailableSlots. Any other catalog clinic (searchClinics), or only a city: date + part_of_day — Dentum confirms by phone. Emergencies are refused (422 error=emergency, call 103).",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/BookRequest"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Booked (pending confirmation)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/BookResponse"
        }
       }
      }
     },
     "409": {
      "description": "Slot unavailable — see alternatives",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "422": {
      "description": "Validation error (consent, date, name/phone, service, unknown_clinic, unknown_city) or emergency → call 103",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Rate limited"
     }
    }
   }
  },
  "/api/cabinet/agent/cities": {
   "get": {
    "operationId": "listCities",
    "summary": "Cities of Uzbekistan with clinic counts and where exact-time booking exists",
    "parameters": [
     {
      "name": "lang",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "uz",
        "ru",
        "en",
        "zh"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Cities"
        }
       }
      }
     }
    }
   }
  },
  "/api/cabinet/agent/clinics": {
   "get": {
    "operationId": "searchClinics",
    "summary": "Search dental clinics (city, service, name, 24/7, near me). Placement is never sold.",
    "parameters": [
     {
      "name": "city",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "Key or name in any language"
     },
     {
      "name": "service",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "q",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "Part of name or address"
     },
     {
      "name": "open24",
      "in": "query",
      "schema": {
       "type": "boolean"
      }
     },
     {
      "name": "online",
      "in": "query",
      "schema": {
       "type": "boolean"
      },
      "description": "Only exact-time (online schedule) clinics"
     },
     {
      "name": "verified",
      "in": "query",
      "schema": {
       "type": "boolean"
      }
     },
     {
      "name": "min_rating",
      "in": "query",
      "schema": {
       "type": "number"
      }
     },
     {
      "name": "lat",
      "in": "query",
      "schema": {
       "type": "number"
      }
     },
     {
      "name": "lon",
      "in": "query",
      "schema": {
       "type": "number"
      }
     },
     {
      "name": "sort",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "catalog",
        "rating",
        "distance"
       ]
      }
     },
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 25
      }
     },
     {
      "name": "offset",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 0
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ClinicSearch"
        }
       }
      }
     },
     "422": {
      "description": "unknown_city / unknown_service",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/cabinet/agent/clinic": {
   "get": {
    "operationId": "getClinic",
    "summary": "Public card of one clinic",
    "parameters": [
     {
      "name": "id",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "lang",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "uz",
        "ru",
        "en",
        "zh"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Clinic"
        }
       }
      }
     },
     "404": {
      "description": "unknown_clinic"
     }
    }
   }
  },
  "/api/cabinet/agent/status": {
   "post": {
    "operationId": "getBookingStatus",
    "summary": "Status of a booking request (number + the phone used for booking; phone only in the body, never in the URL)",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/StatusRequest"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/StatusResponse"
        }
       }
      }
     },
     "404": {
      "description": "not_found (wrong number or phone)"
     },
     "429": {
      "description": "Rate limited"
     }
    }
   }
  },
  "/api/cabinet/agent/doctors": {
   "get": {
    "operationId": "searchDoctors",
    "summary": "Public directory of dentists (verification level 1–3; no phones)",
    "parameters": [
     {
      "name": "city",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "specialty",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "q",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 25
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK"
     },
     "422": {
      "description": "unknown_city"
     }
    }
   }
  }
 },
 "components": {
  "schemas": {
   "Error": {
    "type": "object",
    "properties": {
     "ok": {
      "type": "boolean"
     },
     "error": {
      "type": "string"
     },
     "hint": {
      "type": "string"
     },
     "alternatives": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Day"
      }
     }
    }
   },
   "Day": {
    "type": "object",
    "properties": {
     "date": {
      "type": "string",
      "format": "date"
     },
     "weekday": {
      "type": "string"
     },
     "times": {
      "type": "array",
      "items": {
       "type": "string",
       "pattern": "^\\d{2}:\\d{2}$"
      }
     }
    }
   },
   "Services": {
    "type": "object",
    "properties": {
     "currency": {
      "type": "string"
     },
     "timezone": {
      "type": "string"
     },
     "primary": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "services": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "key": {
         "type": "string"
        },
        "name": {
         "type": "string"
        },
        "category": {
         "type": "string"
        },
        "market_price_from_uzs": {
         "type": [
          "integer",
          "null"
         ]
        },
        "market_price_to_uzs": {
         "type": [
          "integer",
          "null"
         ]
        },
        "exact_time_booking_at": {
         "type": "array",
         "items": {
          "type": "string"
         }
        }
       }
      }
     }
    }
   },
   "Options": {
    "type": "object",
    "properties": {
     "service": {
      "type": "object"
     },
     "exact_time_clinics": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "clinic": {
         "type": "string"
        },
        "name": {
         "type": "string"
        },
        "city": {
         "type": "string"
        },
        "address": {
         "type": "string"
        },
        "price_from_uzs": {
         "type": "integer"
        },
        "price_item": {
         "type": "string"
        },
        "price_list": {
         "type": "string",
         "format": "uri"
        },
        "affiliation_disclosure": {
         "type": "string"
        },
        "next_free": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/Day"
         }
        }
       }
      }
     },
     "concierge": {
      "type": "object"
     }
    }
   },
   "Availability": {
    "type": "object",
    "properties": {
     "clinic": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "timezone": {
      "type": "string"
     },
     "slots": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Day"
      }
     }
    }
   },
   "BookRequest": {
    "type": "object",
    "required": [
     "service",
     "date",
     "patient_name",
     "patient_phone",
     "patient_consent"
    ],
    "properties": {
     "service": {
      "type": "string",
      "description": "Service key from listServices"
     },
     "clinic": {
      "type": "string",
      "description": "Clinic id from searchClinics — any of the 1455 catalog clinics. Optional: without it Dentum matches a clinic in the city."
     },
     "city": {
      "type": "string",
      "default": "toshkent",
      "description": "City key or name in any language (toshkent, Tashkent, Ташкент)"
     },
     "date": {
      "type": "string",
      "format": "date",
      "description": "Asia/Tashkent"
     },
     "time": {
      "type": "string",
      "pattern": "^\\d{2}:\\d{2}$",
      "description": "Required for exact-time clinics"
     },
     "part_of_day": {
      "type": "string",
      "enum": [
       "morning",
       "afternoon",
       "evening"
      ],
      "description": "Preferred window for concierge bookings"
     },
     "patient_name": {
      "type": "string"
     },
     "patient_phone": {
      "type": "string",
      "description": "With country code, e.g. +998901234567"
     },
     "patient_consent": {
      "type": "boolean",
      "const": true,
      "description": "true only if the patient explicitly agreed to the privacy policy"
     },
     "reminders_consent": {
      "type": "boolean"
     },
     "language": {
      "type": "string",
      "enum": [
       "uz",
       "ru",
       "en",
       "zh"
      ]
     },
     "notes": {
      "type": "string",
      "maxLength": 30
     },
     "agent_name": {
      "type": "string",
      "description": "e.g. ChatGPT, Claude, Gemini, Perplexity"
     },
     "symptoms": {
      "type": "string",
      "description": "What bothers the patient (optional). Used only to detect emergencies; not stored."
     },
     "doctor": {
      "type": "integer",
      "description": "Doctor id from searchDoctors — books the doctor’s clinic and notes the doctor"
     }
    }
   },
   "BookResponse": {
    "type": "object",
    "properties": {
     "ok": {
      "type": "boolean"
     },
     "ref": {
      "type": "string",
      "pattern": "^D-\\d{6}-[A-Z0-9]{4}$"
     },
     "status": {
      "type": "string",
      "enum": [
       "pending_confirmation"
      ]
     },
     "mode": {
      "type": "string",
      "enum": [
       "exact_time",
       "concierge"
      ]
     },
     "service": {
      "type": "string"
     },
     "clinic": {
      "type": [
       "string",
       "null"
      ]
     },
     "clinic_name": {
      "type": "string"
     },
     "date": {
      "type": "string"
     },
     "time": {
      "type": "string"
     },
     "part_of_day": {
      "type": "string"
     },
     "telegram_link": {
      "type": "string",
      "format": "uri",
      "description": "Give this to the user: confirmation and reminders in Telegram"
     },
     "next_steps": {
      "type": "string"
     },
     "affiliation_disclosure": {
      "type": "string"
     }
    }
   },
   "City": {
    "type": "object",
    "properties": {
     "key": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "clinics": {
      "type": "integer"
     },
     "exact_time_clinics": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "booking": {
      "type": "string"
     }
    }
   },
   "Cities": {
    "type": "object",
    "properties": {
     "total_clinics": {
      "type": "integer"
     },
     "data_as_of": {
      "type": "string"
     },
     "cities": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/City"
      }
     },
     "concierge": {
      "type": "object"
     }
    }
   },
   "ClinicSummary": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "city": {
      "type": "string"
     },
     "address": {
      "type": "string"
     },
     "rating": {
      "type": [
       "number",
       "null"
      ],
      "description": "From 2GIS/OSM listing (attribution required)"
     },
     "reviews": {
      "type": "integer"
     },
     "verified": {
      "type": "boolean",
      "description": "Owner confirmed the listing via Dentum"
     },
     "prices_published": {
      "type": "boolean"
     },
     "online_schedule": {
      "type": "boolean",
      "description": "Exact-time booking available"
     },
     "open24x7_confirmed": {
      "type": "boolean"
     },
     "open24x7_listed": {
      "type": "boolean",
      "description": "Only as listed in 2GIS/OSM"
     },
     "distance_km": {
      "type": "number"
     },
     "booking_mode": {
      "type": "string",
      "enum": [
       "exact_time",
       "dentum_confirms_time"
      ]
     },
     "page": {
      "type": [
       "string",
       "null"
      ]
     },
     "affiliation_disclosure": {
      "type": "string"
     }
    }
   },
   "ClinicSearch": {
    "type": "object",
    "properties": {
     "total": {
      "type": "integer"
     },
     "returned": {
      "type": "integer"
     },
     "offset": {
      "type": "integer"
     },
     "sort": {
      "type": "string"
     },
     "filters": {
      "type": "object"
     },
     "clinics": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/ClinicSummary"
      }
     },
     "how_to_book": {
      "type": "string"
     },
     "attribution": {
      "type": "string"
     }
    }
   },
   "Clinic": {
    "allOf": [
     {
      "$ref": "#/components/schemas/ClinicSummary"
     },
     {
      "type": "object",
      "properties": {
       "category": {
        "type": [
         "string",
         "null"
        ]
       },
       "city_name": {
        "type": "string"
       },
       "coordinates": {
        "type": [
         "object",
         "null"
        ]
       },
       "hours": {
        "type": "object"
       },
       "services": {
        "type": "array",
        "items": {
         "type": "string"
        }
       },
       "phone": {
        "type": "null",
        "description": "Clinic phones are not published — book through Dentum"
       },
       "schedule": {
        "type": "object"
       },
       "prices": {
        "type": "object"
       },
       "price_list": {
        "type": "string"
       },
       "next_free": {
        "type": "array",
        "items": {
         "$ref": "#/components/schemas/Day"
        }
       }
      }
     }
    ]
   },
   "StatusRequest": {
    "type": "object",
    "required": [
     "ref",
     "phone"
    ],
    "properties": {
     "ref": {
      "type": "string",
      "pattern": "^D-\\d{6}-[A-Z0-9]{4}$"
     },
     "phone": {
      "type": "string",
      "description": "The phone used for the booking"
     }
    }
   },
   "StatusResponse": {
    "type": "object",
    "properties": {
     "ok": {
      "type": "boolean"
     },
     "ref": {
      "type": "string"
     },
     "status": {
      "type": "string",
      "enum": [
       "received",
       "in_progress",
       "confirmed",
       "completed",
       "no_show",
       "declined"
      ]
     },
     "status_text": {
      "type": "string"
     },
     "service": {
      "type": "string"
     },
     "clinic": {
      "type": [
       "string",
       "null"
      ]
     },
     "clinic_name": {
      "type": [
       "string",
       "null"
      ]
     },
     "appointment": {
      "type": [
       "string",
       "null"
      ]
     },
     "created_at": {
      "type": "string"
     }
    }
   }
  },
  "securitySchemes": {
   "partnerKey": {
    "type": "http",
    "scheme": "bearer",
    "bearerFormat": "dp_live_…",
    "description": "Optional partner key: 600 reads/min and 60 bookings per 10 min instead of the public 60/min and 6 per 10 min, usage accounting, bookings tagged with the partner name. Request: https://dentum.uz/en/agents/#partner"
   }
  }
 },
 "security": [
  {},
  {
   "partnerKey": []
  }
 ]
}