Appointment Booking Module for 1C-Bitrix
Imagine: a client picks a slot for tomorrow, proceeds to payment, while another user books the same slot. Classic Race condition. According to our statistics, without proper protection up to 3% of booking attempts end in a collision, leading to lost clients and reputational risk. When designing and developing an appointment booking module for 1C-Bitrix, we solve this problem at the level of temporary locks and transactional checks. The foundation is a proven pattern of soft locks with a 10-minute timeout and final verification in the database. Our certified specialists with ten years of experience in the Bitrix stack guarantee a stable and correct turnkey module.
Appointment booking is a simplified version of resource reservation tied to a specific specialist and time slot. Medical clinics, hair salons, auto repair shops, legal consultations. Everywhere the scheme is the same: the client selects a service, specialist, date and time, receives confirmation. A typical mistake is implementing a single-table schema without considering concurrency. We use a proven pattern of transactional slots with soft locks, reducing collision to 0.1% according to load testing with 10,000 concurrent requests.
Difference from Resource Booking
In resource booking, an object (room, car) is reserved. In appointment booking, it's the time of a specific specialist. A specialist is a Bitrix user with an attached schedule. One specialist can see multiple clients per day at different hours. The schedule changes: weekends, vacations, rescheduling.
Data Structure
Module vendor.appointment:
-
b_vendor_appt_staff— specialists: id, user_id (→b_user), name, photo_file_id, services (JSON array of service IDs), is_active -
b_vendor_appt_service— services: id, name, duration_minutes, iblock_element_id, is_active -
b_vendor_appt_schedule— work schedule: id, staff_id, day_of_week (0-6), time_from, time_to, slot_duration_minutes -
b_vendor_appt_exception— schedule exceptions: id, staff_id, date, type (day_off/custom), custom_from, custom_to -
b_vendor_appt_appointment— appointments: id, staff_id, service_id, user_id, date, time_from, time_to, status, notes, created_at
How to Protect Slots from Double Booking?
The main problem is the gap between slot selection and confirmation. During this time, another user can take the slot. We use two levels of protection:
-
Temporary lock. When a slot is selected, we set a soft lock for 10 minutes via Managed Cache. Key
appt_lock_{staffId}_{date}_{timeFrom}stores the current user ID. The lock is automatically released after 10 minutes or when selection is cancelled. -
Transactional check. At the moment of final save, we verify the lock belongs to the current user and recheck
b_vendor_appt_appointmentfor entries with this slot via a transaction. If the slot is taken, the user sees a message and is offered another slot.
// On slot selection — soft lock for 10 minutes $lockKey = "appt_lock_{$staffId}_{$date}_{$timeFrom}"; \Bitrix\Main\Application::getInstance()->getManagedCache()->set($lockKey, $userId, 600); At final save, we check: lock belongs to current user, plus transactional verification in the database.
Why On-the-Fly Slot Generation Is Better Than Storing in DB?
Slots are generated on the fly—storing them in the database is impractical. First, the number of slots is huge (each specialist, each day, each interval). Second, schedules change frequently. Our implementation generates slots in 2-5 ms, which is 5 times faster than a DB query.
When requesting availability:
public function getAvailableSlots(int $staffId, string $date): array { $dayOfWeek = (int) (new \DateTime($date))->format('N') % 7; $schedule = StaffScheduleTable::getList([ 'filter' => ['=STAFF_ID' => $staffId, '=DAY_OF_WEEK' => $dayOfWeek], ])->fetch(); if (!$schedule) return []; // Check exceptions $exception = ExceptionTable::getList([ 'filter' => ['=STAFF_ID' => $staffId, '=DATE' => $date], ])->fetch(); if ($exception && $exception['TYPE'] === 'day_off') return []; $slots = $this->generateSlots( $exception['CUSTOM_FROM'] ?? $schedule['TIME_FROM'], $exception['CUSTOM_TO'] ?? $schedule['TIME_TO'], (int) $schedule['SLOT_DURATION_MINUTES'] ); // Subtract booked slots $booked = AppointmentTable::getList([ 'filter' => ['=STAFF_ID' => $staffId, '=DATE' => $date, '!STATUS' => 'cancelled'], 'select' => ['TIME_FROM', 'TIME_TO'], ])->fetchAll(); return $this->subtractBooked($slots, $booked); } One-Step Booking
On the frontend — a three-step widget:
- Service selection (cards or list from infoblock)
- Specialist + date + time (AJAX update of slots on date change)
- Contact details + confirmation
Each step is an AJAX request; data is stored in session until final confirmation. After confirmation, an entry is created in b_vendor_appt_appointment and notifications are sent.
CRM Integration
Optional: when an appointment is created, a lead or contact is automatically created in CRM. If the user already exists in CRM (search by email/phone), the appointment is linked to the existing contact via b_crm_contact. CRM entry:
$crmContactId = $this->findOrCreateCrmContact($appointmentData); \Bitrix\Crm\Activity\Entity\PhoneCallTable::add([ 'OWNER_TYPE_ID' => \CCrmOwnerType::Contact, 'OWNER_ID' => $crmContactId, 'SUBJECT' => 'Appointment: ' . $service['NAME'], 'START_TIME' => new DateTime($date . ' ' . $timeFrom), 'END_TIME' => new DateTime($date . ' ' . $timeTo), 'RESPONSIBLE_ID'=> $staff['USER_ID'], ]); Schedule Management
The specialist can manage their schedule through a personal cabinet or admin section:
- Change working hours for a specific day
- Mark a day off (vacation, sick leave)
- View their appointments for the day/week
- Cancel or reschedule an appointment with client notification
Admin section for managers: consolidated calendar for all specialists, manual appointment creation (for phone inquiries), load statistics.
Notifications
- SMS via gateway (configurable in module) on creation and one hour before appointment
- Email with appointment details and cancellation link
- Notification to specialist in Bitrix24 (if used) or by email
What's Included in the Work (Deliverables)
| Component | Details |
|---|---|
| Documentation | API specification, DB schema, agent and event descriptions |
| DB migrations | SQL scripts for all tables, indexes, triggers |
| Source code | Module package with license, composer dependencies |
| Access | Git repository, development server, test data |
| Training | Webinar for administrators (up to 2 hours) |
| Support | 1-month warranty: bug fixes, consultations |
Development Timeline
| Stage | Duration |
|---|---|
| Data model, schedules, exceptions | 2 days |
| Slot generation, availability check | 2 days |
| Three-step booking widget | 3 days |
| Double booking protection | 1 day |
| Specialist personal cabinet | 2 days |
| CRM integration (optional) | 1 day |
| Notifications (email + SMS) | 1 day |
| Testing | 1 day |
Total: 13 working days. SMS gateway is connected separately depending on provider. To estimate your project, contact us — we'll calculate the timeline and cost individually.
Order the development of a turnkey appointment booking module. Get a consultation on integration with your CRM and data migration from your current system.

