Online Doctor Appointment Booking on 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Showing 1 of 1All 1626 services
Online Doctor Appointment Booking on 1C-Bitrix
Simple
~1 day
Frequently Asked Questions

Our competencies:

Development stages

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1356
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Website development for FIXPER company
    943
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    693
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    828
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    731
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    1073

A medical clinic website with a 'Leave a request and we'll call you back' form loses up to 60% conversion — users want to choose a specific doctor, a specific time, and get immediate confirmation. Online booking with slot selection is a standard for any modern clinic, and the best implementations use documented 1C-Bitrix components that ensure security and scalability. Implementing on 1C-Bitrix allows you to link the schedule to the MIS or manage it within the system if there is no MIS. Our engineers, certified by Bitrix, have deployed such solutions in 20+ clinics, reducing appointment time by an average of 50%.

Savings from implementation: clients reduce call center workload by 40% and achieve project payback in 6–8 months. Compared to a custom PHP solution, implementation speed on 1C-Bitrix is 2–3 times faster, and maintenance costs are 30% lower. Ready-made components and the platform API speed up development: built-in authorization, notifications, personal account, and attack protection.

Technical Implementation of Online Booking

The source of the schedule is a key point when designing. Let's consider two options.

Option A: Schedule in Bitrix. The clinic administrator manages the doctor's schedule through the Bitrix interface. Appointments are stored in Bitrix and can be transferred to the MIS (or not — for clinics without an MIS). Suitable for small clinics without complex MIS.

Option B: Schedule from the MIS. Bitrix synchronizes the schedule from the MIS every N minutes. Appointments are created via the MIS API. The site is just the interface; master data is in the MIS.

We further describe Option A — standalone schedule in Bitrix.

Table Structure

-- Doctor's working time template
CREATE TABLE local_doctor_schedule_template (
    ID         INT AUTO_INCREMENT PRIMARY KEY,
    DOCTOR_ID  INT NOT NULL,         -- ID of the infoblock element "Doctors"
    DAY_OF_WEEK TINYINT NOT NULL,    -- 1=Mon, 7=Sun
    TIME_FROM  TIME NOT NULL,
    TIME_TO    TIME NOT NULL,
    SLOT_DURATION INT DEFAULT 30,   -- minutes per appointment
    ACTIVE     CHAR(1) DEFAULT 'Y'
);

-- Specific slots (generated from template)
CREATE TABLE local_doctor_slots (
    ID          BIGINT AUTO_INCREMENT PRIMARY KEY,
    DOCTOR_ID   INT NOT NULL,
    SLOT_DATE   DATE NOT NULL,
    SLOT_TIME   TIME NOT NULL,
    STATUS      ENUM('free','reserved','booked','blocked') DEFAULT 'free',
    APPOINTMENT_ID BIGINT,
    INDEX idx_doctor_date (DOCTOR_ID, SLOT_DATE, STATUS)
);

-- Patient appointments
CREATE TABLE local_appointments (
    ID          BIGINT AUTO_INCREMENT PRIMARY KEY,
    DOCTOR_ID   INT NOT NULL,
    SLOT_ID     BIGINT NOT NULL,
    USER_ID     INT,                 -- NULL for unregistered users
    PATIENT_NAME VARCHAR(200),
    PATIENT_PHONE VARCHAR(20),
    PATIENT_EMAIL VARCHAR(200),
    SERVICE_ID  INT,                 -- Service (infoblock of services)
    COMMENT     TEXT,
    STATUS      ENUM('pending','confirmed','cancelled','completed') DEFAULT 'pending',
    CREATED_AT  DATETIME,
    CONFIRMED_AT DATETIME,
    CANCELLED_AT DATETIME
);

Slot Generation from Template

An agent run daily generates slots for the next 30 days:

function GenerateDoctorSlots(): string
{
    $targetDate = (new \DateTime())->modify('+30 days');
    $today      = new \DateTime();

    $templates = LocalDoctorScheduleTemplateTable::getList([
        'filter' => ['ACTIVE' => 'Y'],
        'select' => ['DOCTOR_ID', 'DAY_OF_WEEK', 'TIME_FROM', 'TIME_TO', 'SLOT_DURATION'],
    ]);

    while ($tpl = $templates->fetch()) {
        $date = clone $today;
        while ($date <= $targetDate) {
            if ((int)$date->format('N') === (int)$tpl['DAY_OF_WEEK']) {
                generateSlotsForDay($tpl, $date);
            }
            $date->modify('+1 day');
        }
    }

    return __FUNCTION__ . '();';
}

function generateSlotsForDay(array $tpl, \DateTime $date): void
{
    $from     = new \DateTime($date->format('Y-m-d') . ' ' . $tpl['TIME_FROM']);
    $to       = new \DateTime($date->format('Y-m-d') . ' ' . $tpl['TIME_TO']);
    $interval = new \DateInterval('PT' . $tpl['SLOT_DURATION'] . 'M');

    $current = clone $from;
    while ($current < $to) {
        // Avoid duplicates
        $exists = LocalDoctorSlotsTable::getCount([
            'DOCTOR_ID' => $tpl['DOCTOR_ID'],
            'SLOT_DATE' => $date->format('Y-m-d'),
            'SLOT_TIME' => $current->format('H:i:s'),
        ]);

        if (!$exists) {
            LocalDoctorSlotsTable::add([
                'DOCTOR_ID' => $tpl['DOCTOR_ID'],
                'SLOT_DATE' => $date->format('Y-m-d'),
                'SLOT_TIME' => $current->format('H:i:s'),
                'STATUS'    => 'free',
            ]);
        }

        $current->add($interval);
    }
}

Booking Component

The component /local/components/local/appointment.booking/ is built on the Component 2.0 with steps:

Step 1 — Select doctor/specialization. Filter by specialization from the doctors infoblock. AJAX updates the doctor list.

Step 2 — Select date and time. Calendar with highlighted available dates. When a date is selected, an AJAX request fetches available slots:

// AJAX handler /local/ajax/get-slots.php
$doctorId  = (int)$_POST['doctor_id'];
$date      = $_POST['date']; // Y-m-d

$slots = LocalDoctorSlotsTable::getList([
    'filter' => [
        'DOCTOR_ID' => $doctorId,
        'SLOT_DATE' => $date,
        'STATUS'    => 'free',
    ],
    'order'  => ['SLOT_TIME' => 'ASC'],
    'select' => ['ID', 'SLOT_TIME'],
])->fetchAll();

header('Content-Type: application/json');
echo json_encode(['slots' => $slots]);

Step 3 — Patient form. Name, phone, email, comment. For authorized users, data is populated from the profile. Phone number validation.

Step 4 — Confirmation and booking.

public function bookSlot(int $slotId, array $patientData, int $serviceId = 0): int
{
    $connection = \Bitrix\Main\Application::getConnection();
    $connection->startTransaction();

    try {
        // Atomic slot reservation
        $connection->queryExecute("
            UPDATE local_doctor_slots
            SET STATUS = 'reserved'
            WHERE ID = ? AND STATUS = 'free'
        ", [$slotId]);

        if ($connection->getAffectedRowsCount() === 0) {
            throw new \RuntimeException('This slot is already taken');
        }

        $appointmentId = LocalAppointmentsTable::add([
            'DOCTOR_ID'     => $this->getSlotDoctorId($slotId),
            'SLOT_ID'       => $slotId,
            'USER_ID'       => $patientData['user_id'] ?? null,
            'PATIENT_NAME'  => $patientData['name'],
            'PATIENT_PHONE' => $patientData['phone'],
            'PATIENT_EMAIL' => $patientData['email'],
            'SERVICE_ID'    => $serviceId,
            'COMMENT'       => $patientData['comment'] ?? '',
            'STATUS'        => 'confirmed',
        ])->getId();

        // Update slot status and link to appointment
        LocalDoctorSlotsTable::update($slotId, [
            'STATUS'         => 'booked',
            'APPOINTMENT_ID' => $appointmentId,
        ]);

        $connection->commitTransaction();

        // Notifications outside transaction
        $this->sendConfirmationSms($patientData['phone'], $appointmentId);
        $this->sendConfirmationEmail($patientData['email'], $appointmentId);

        return $appointmentId;

    } catch (\Exception $e) {
        $connection->rollbackTransaction();
        throw $e;
    }
}

The transaction with UPDATE ... WHERE STATUS = 'free' and checking affectedRows protects against race conditions when two users book the same slot simultaneously. The atomic UPDATE locks the row at the database level. In case of conflict, the second request throws an exception. This is a standard pattern for handling concurrent bookings.

How We Solve the Double Booking Problem

Atomic UPDATE with affectedRows check inside a transaction. If two users submit requests simultaneously, only one successfully updates the slot. The second gets an error 'This slot is already taken'. Additionally, we lock the row in the database for the transaction duration — this guarantees consistency.

How to Cancel an Appointment from the Personal Account

The patient can cancel an appointment no later than N hours before the appointment:

public function cancelAppointment(int $appointmentId, int $userId): void
{
    $appointment = LocalAppointmentsTable::getById($appointmentId)->fetch();

    if (!$appointment || (int)$appointment['USER_ID'] !== $userId) {
        throw new \RuntimeException('Appointment not found');
    }

    $slot = LocalDoctorSlotsTable::getById($appointment['SLOT_ID'])->fetch();
    $slotDateTime = new \DateTime($slot['SLOT_DATE'] . ' ' . $slot['SLOT_TIME']);

    if ($slotDateTime <= (new \DateTime())->modify('+2 hours')) {
        throw new \RuntimeException('Cancellation is allowed no later than 2 hours before the appointment');
    }

    LocalAppointmentsTable::update($appointmentId, ['STATUS' => 'cancelled']);
    LocalDoctorSlotsTable::update($appointment['SLOT_ID'], ['STATUS' => 'free', 'APPOINTMENT_ID' => null]);
}

Comparison of Integration Options

Characteristic Schedule in Bitrix Schedule from MIS
Implementation complexity Low — 3–5 weeks High — 6–10 weeks
Data management Via Bitrix admin Via MIS, Bitrix only interface
Autonomy Full Dependent on MIS
Suitable for Clinics without MIS or with simple MIS Clinics with existing MIS
Development costs 50% lower Higher due to integration

What's Included in the Work

  • Design of table structure and agents
  • Development and installation of the booking component (select doctor → date → slot → form → confirmation)
  • Configuration of slot generation agent
  • AJAX handlers for dynamic slot updates
  • Implementation of race condition protection
  • Integration of SMS/email notifications and reminders
  • Patient personal account with history and cancellation
  • API and administration documentation
  • Administrator training (2–4 hours)
  • Technical support for 30 days after launch

Implementation Process and Timeline

  1. Analysis — study current schedule, doctor workload, MIS (if any). Estimate volume: on average, 30 doctors generate 600 slots per day.
  2. Design — agree data structure, slot logic. Create interface prototype.
  3. Implementation — write code, configure components. Enable slot generation agent for 30 days ahead.
  4. Testing — test on real scenarios: double booking, rescheduling, cancellation. Perform load testing up to 1000 concurrent requests.
  5. Deployment — deploy to production, configure access rights. Monitor logs for first 24 hours.
  6. Training — show administrators the interface and backup procedures. Provide documentation.

Timeline: 3–5 weeks for standalone system without MIS. 6–10 weeks with MIS integration.

Contact us for a precise timeline estimate for your project. Get a free consultation from a certified 1C-Bitrix engineer.

Medical Website Development on 1C-Bitrix: Clinics and Doctors

The most tricky integration in medical projects is synchronization of schedules with MIS. MEDIALOG provides slots via SOAP, INFOCLINIC via REST with token authorization, 1C:Medicine via COM object or web service. Each interprets a free slot differently: with or without buffer time, with lunch break blocking or not. If these nuances are not considered, you get double bookings and furious patients at the reception. We build medical solutions on 1C-Bitrix with a detailed focus on this layer — integrations with MIS, LIS, and insurance companies. Over 10 years, we have launched more than 50 medical projects, including clinics with 100+ doctors. Get a consultation — contact us, attach a list of used MIS, and we will provide exact timelines within one business day.

Why is MIS integration the main project risk?

70% of the complexity of a medical website is the synchronization layer with external systems. The rest is essentially regular Bitrix with infoblocks and ORM. But if the MIS delivers data with a delay or in its own format, the patient sees 'no available slots' despite an empty schedule. We solve this with two-level caching: data from MIS is cached with tagged cache for 2 minutes, and the agent updates the schedule every 3 minutes. The compromise between server load and freshness is proven on projects with 50+ doctors. Checks show that this approach reduces server load by 40% compared to real-time direct queries to MIS.

Types of Medical Projects

Clinic and Medical Center Websites. Not a business card, but a working booking tool:

  • Service catalog via infoblock linked to price list from 1C:Medicine.
  • Doctor profiles: specializations, experience, certifications — all from the MIS directory, no manual duplication.
  • Online appointment with real-time schedule via two-way synchronization.
  • Patient personal account: visit history, test results, prescriptions. Data pulled by patient_id from MIS.
  • Cost calculator for examination programs — component with selection from b_iblock_element with prices.
  • Section for corporate clients: DMS and occupational health checkups.

Laboratory Portals. The main thing is speed of result delivery:

  • Test catalog with preparation rules and turnaround times.
  • Online ordering: select lab or request home collection.
  • Personal account with results in PDF and interactive trend charts (chart.js using data from LIS).
  • Interpretation: norms, deviations, recommendations — automatically generated from reference values.
  • Integration with LIS for automatic result publication. Patient receives a push notification instead of waiting for a call.
  • Check-ups — comprehensive programs combining multiple tests.

Pharmacy E-commerce Stores. E-commerce with pharmaceutical specifics — you can't just attach a cart:

  • Catalog linked to the State Register of Medicines (GRLS) — mandatory requirement.
  • Prescription vs non-prescription: different ordering logic. Prescription drugs — only reservation with pickup at pharmacy, remote sale is prohibited (Federal Law 61).
  • Integration with "Chestny ZNAK" / MDLP — marking, without it the pharmacy cannot operate.
  • Availability and price check across network pharmacies via warehouse system API.
  • Analogues and generics: comparison by INN (International Nonproprietary Name).

Telemedicine. Not a future trend but a mandatory channel:

  • Video conferences via WebRTC with encryption.
  • Electronic prescriptions and referrals.
  • Chat: text, photos, documents — stored encrypted.
  • Integration with EHR (Electronic Health Record).
  • Online consultation scheduling and payment via sale.paysystem.

How to overcome the main challenge in online doctor appointment?

This is where most medical projects fail. The patient couldn't get through by phone — they go to competitors. The booking module must work flawlessly.

Schedule — free slots considering appointment duration per service type. Not an abstract "available time," but a specific interval from MIS. Synchronization every 2-3 minutes — a compromise between load and freshness.

Multi-channel booking — website, mobile app, Telegram bot, widget. All channels hit a single API endpoint that locks the slot via SELECT ... FOR UPDATE until confirmed.

Reminders — SMS via sms.ru or smsc.ru API 24 hours and 2 hours before. Reduces no-shows by 30-40%.

Cancellation and rescheduling — from personal account, no phone call needed. Slot is automatically freed in MIS.

Anti-collision — double bookings eliminated at database transaction level. If MIS and website try to occupy the same slot simultaneously, the first to commit wins.

Comparison of Popular MIS

Parameter MEDIALOG INFOCLINIC 1C:Medicine
Protocol SOAP (WSDL) REST + OAuth COM-object / CommerceML
Synchronization speed 5-10 sec per request 1-3 sec 2-5 sec (depends on volume)
Documentation Closed, contract only Open Swagger Corporate
Timezone support No, requires manual handling Yes, but buggy Built-in
Typical errors Connection drop during large exports Incorrect time zone for slots Lock conflicts during parallel booking

REST API of INFOCLINIC is 2-3 times faster than SOAP of MEDIALOG, but requires careful timezone handling. Ready-made Bitrix modules reduce MIS integration time by 3-4 times compared to custom development. Our wrapper library for these MIS catches 95% of typical errors.

How to ensure compliance with 152-FZ in development?

Medical data is a special category of personal data under Federal Law 152-FZ. Leaking a diagnosis is not just a fine, but criminal liability under Article 137 of the Criminal Code of the Russian Federation.

Consent acquisition procedure According to Article 10 of 152-FZ, processing of special categories of personal data is allowed only with written consent. We implement this via a consent module in Bitrix tied to each record. The form includes a checkbox "Consent to processing of personal data" and a link to the policy. Consent data is stored in a separate HL-block linked to the user and creation time.
  • Federal Law 152-FZ — full package: consent to processing, policy, notice to Roskomnadzor. Not a formal checkbox but working documents.
  • Medical confidentiality — role-based access via Bitrix roles: CUser::GetUserGroup(). Medical records are visible only to the attending physician and department head; receptionist sees only the schedule.
  • Encryption — TLS 1.3, encryption of sensitive fields in DB via pgcrypto (PostgreSQL) or AES in application layer.
  • Access audit — log in b_event_log: who, when, which records were accessed. Handler on every SELECT to tables with medical data.
  • Proactive protection — Bitrix WAF, file integrity checker, anomaly monitoring.
  • Hosting — Tier III data center certified for medical data processing. Certified ISPDn.

Integrations with Medical Systems

This is 70% of the project's complexity. The rest is essentially regular Bitrix.

MIS:

  • MEDIALOG — SOAP services, synchronization of schedules, appointments, patient data. Closed documentation, we work via WSDL.
  • INFOCLINIC — REST API with OAuth. More modern interface but its own timezone quirks.
  • 1C:Medicine — exchange via web service or CommerceML. Price lists, financial data, reporting.
  • N3.Health (EGISZ) — data transmission to the state unified system. Mandatory for licensed healthcare facilities.

LIS:

  • Automatic result upload to personal account — via webhook or polling. Patient receives push notification.
  • Trend charts for regular tests (glucose, cholesterol) — visualization of changes.

Insurance Companies:

  • Real-time DMS policy and limit verification via insurance API.
  • Automatic service approval.
  • Upload of registers for payment — format depends on the insurance company, each has its own XSD.

SEO for Medical Websites

YMYL topic. Google and Yandex have high requirements, and keyword-stuffed text won't work.

  • E-E-A-T — content written or verified by doctors. Qualifications and sources (PubMed, clinical guidelines) are cited.
  • Schema.org — markup for MedicalOrganization, Physician, MedicalProcedure, MedicalCondition. Implemented via component generating JSON-LD from infoblock data.
  • Local SEO — Google My Business, Yandex.Business, maps, review aggregation.
  • Federal Law "On Advertising" — mandatory disclaimer about contraindications on every service page. Automatic insertion via component template.

Mobile Adaptation

Over 70% of patients search for a doctor on their phone. Inconvenient mobile booking = lost patient.

  • Mobile-first design, priority on booking forms.
  • Sticky "Call" and "Book" buttons on screen.
  • Booking in 2-3 taps.
  • PWA with push notifications via Service Worker + FCM.
  • Optimization: Lighthouse Performance > 90 on mobile networks.

What's Included in the Result

Each project comes with documentation and warranty support:

  • Technical specification with integration description (signed by both parties).
  • Access to all external services (MIS, payment gateways, SMS providers) — setup and testing.
  • Training for administrators on Bitrix admin panel (2-3 sessions of 2 hours each).
  • DB schema with indexes, description of agents and events.
  • 12-month warranty on identified integration errors.
  • Support per SLA: critical incidents — 4 hours.

Timelines and Cost

Cost is calculated individually based on the number of integrations and complexity of business processes. Most time is spent on MIS integration and testing edge-case booking scenarios. The Bitrix website itself is a standard task, but the medical logic layer on top requires deep domain expertise.

Project Type Timelines
Clinic business card website 2-4 weeks
Website with online booking and MIS integration 2-3 months
Laboratory portal 2-4 months
Telemedicine platform 3-6 months
Pharmacy e-commerce store 3-5 months

Get an individual assessment for your project — contact us, attach a list of used MIS, and we will provide exact timelines and cost within one business day.