Online Appointment Booking: Bitrix & MIS Synchronization
Your private clinic's website accepts online appointments with doctors. The MIS — Medical Information System — is the clinic's operating system: doctor schedules, medical history, electronic health records, service accounting, cash register. MIS — Medical Information System. The challenge: appointments from the site must automatically appear in the MIS schedule, and vacant slots must be displayed on the site in real time. Each hour of downtime or manual data transfer costs up to 30% of lost patients — we've seen this repeatedly.
The MIS market is diverse: Infoclinic, 1C:Medicine, qMS, Medesk, Renaissance-M, ArchiMed+, Medods — each has its own API (or lack thereof). The integration architecture of 1C-Bitrix with the MIS depends on the specific system. We guarantee selecting the optimal scenario and turnkey implementation with full testing.
Typical Integration Scenarios
Scenario A: MIS provides REST/SOAP API. The site directly calls the MIS API to fetch schedules and book a patient. This is the cleanest option, but not all MIS support it.
Scenario B: Intermediate broker. The MIS publishes the schedule to an intermediate database (PostgreSQL or MySQL), the site reads from there. Booking on the site creates a request in an intermediate table, and the MIS picks it up via cron.
Scenario C: Integration bus. For large clinics with multiple MIS and numerous systems — a dedicated integration service (e.g., based on RabbitMQ or Apache Kafka) that synchronizes data between systems.
Which Integration Scenario to Choose?
The choice of scenario is determined by budget, number of systems, and latency requirements. Below is a comparison of key parameters.
| Parameter | REST API | Intermediate DB | Integration Bus |
|---|---|---|---|
| Time to implement | 5–8 weeks | 8–14 weeks | from 12 weeks |
| Data latency | real-time | 1–5 minutes | real-time |
| Load on MIS | high | low (read-only) | balanced |
| Fault tolerance | depends on MIS | high (cached in DB) | high (queue) |
REST API is 2–3 times faster to implement than intermediate database and provides real-time data, but requires a stable endpoint. The intermediate database suits MIS without API or with strict limits. The integration bus is for complex landscapes.
Why REST API Integration Is Optimal?
REST API is the fastest and most transparent integration method. In 90% of cases, we use it: the client gets real-time data, and the codebase remains clean. Below is an example implementation for Medesk — one of the popular MIS.
class MedeskApiClient
{
private string $apiKey;
private string $baseUrl = 'https://api.medesk.net/api/v2';
public function getDoctorSchedule(int $doctorId, string $dateFrom, string $dateTo): array
{
return $this->request('GET', '/schedules', [
'doctor_id' => $doctorId,
'from' => $dateFrom,
'to' => $dateTo,
'include' => 'free_slots',
]);
}
public function createAppointment(array $patientData, int $slotId): array
{
return $this->request('POST', '/appointments', [
'slot_id' => $slotId,
'patient' => [
'first_name' => $patientData['name'],
'last_name' => $patientData['surname'],
'phone' => $patientData['phone'],
'email' => $patientData['email'],
'birth_date' => $patientData['birth_date'],
],
'comment' => $patientData['comment'] ?? '',
'source' => 'website',
]);
}
public function cancelAppointment(int $appointmentId, string $reason = ''): array
{
return $this->request('DELETE', "/appointments/{$appointmentId}", [
'reason' => $reason,
]);
}
private function request(string $method, string $path, array $data = []): array
{
$url = $this->baseUrl . $path;
if ($method === 'GET' && $data) {
$url .= '?' . http_build_query($data);
}
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
"Authorization: Bearer {$this->apiKey}",
],
CURLOPT_POSTFIELDS => in_array($method, ['POST', 'PUT', 'PATCH'])
? json_encode($data) : null,
]);
$response = json_decode(curl_exec($ch), true);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode >= 400) {
\Bitrix\Main\Diag\Debug::writeToFile(
"MIS API Error {$httpCode}: " . json_encode($response),
'MIS',
'/local/logs/mis-integration.log'
);
throw new \RuntimeException("MIS API error: {$httpCode}");
}
return $response ?? [];
}
}
Why Schedule Caching Is Critical?
Directly calling the MIS API on every doctor page visit is a bad idea: the MIS can be slow or have request limits (e.g., 100 requests per minute). Caching reduces the load on the MIS by 10–20 times and speeds up page load to 200 ms. Implementation details:
class DoctorScheduleService
{
private MedeskApiClient $mis;
public function getAvailableSlots(int $doctorId, string $date): array
{
$cacheKey = "doctor_slots_{$doctorId}_{$date}";
$cacheTtl = 180; // 3 миnyты — баланс актуальности и нагрузки
$cache = \Bitrix\Main\Data\Cache::createInstance();
if ($cache->initCache($cacheTtl, $cacheKey, '/mis/slots/')) {
return $cache->getVars()['slots'];
}
$schedule = $this->mis->getDoctorSchedule($doctorId, $date, $date);
$slots = $this->formatSlots($schedule);
$cache->startDataCache();
$cache->endDataCache(['slots' => $slots]);
return $slots;
}
public function bookSlot(int $slotId, array $patientData): array
{
$result = $this->mis->createAppointment($patientData, $slotId);
// Инвалидируем кеш расписания для этого врача
$date = date('Y-m-d');
$doctorId = $this->getSlotDoctorId($slotId);
\Bitrix\Main\Data\Cache::clearByTag("doctor_slots_{$doctorId}_{$date}");
// Сохраняем запись в Битрикс
$this->saveAppointmentInBitrix($result, $patientData);
return $result;
}
}
Storing Appointments in Bitrix
We duplicate appointments in Bitrix — for history, notifications, and operation without the MIS when it's unavailable:
class AppointmentTable extends \Bitrix\Main\ORM\Data\DataManager
{
public static function getTableName(): string { return 'local_mis_appointments'; }
public static function getMap(): array
{
return [
new \Bitrix\Main\ORM\Fields\IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
new \Bitrix\Main\ORM\Fields\IntegerField('USER_ID'),
new \Bitrix\Main\ORM\Fields\IntegerField('MIS_APPOINTMENT_ID'),
new \Bitrix\Main\ORM\Fields\IntegerField('DOCTOR_ID'),
new \Bitrix\Main\ORM\Fields\DatetimeField('APPOINTMENT_TIME'),
new \Bitrix\Main\ORM\Fields\StringField('STATUS'), // booked|confirmed|cancelled|completed
new \Bitrix\Main\ORM\Fields\StringField('SERVICE_NAME'),
new \Bitrix\Main\ORM\Fields\StringField('PATIENT_PHONE'),
new \Bitrix\Main\ORM\Fields\DatetimeField('CREATED_AT'),
];
}
}
Patient Notifications
After booking — SMS and email confirmation via Bitrix. Reminders 24 hours and 2 hours before the appointment. Reminders are implemented via a Bitrix agent that checks appointments every hour:
function SendMisAppointmentReminders(): string
{
$now = new \Bitrix\Main\Type\DateTime();
$in24h = (new \DateTime())->modify('+24 hours');
$in2h = (new \DateTime())->modify('+2 hours');
$appointments = AppointmentTable::getList([
'filter' => [
'STATUS' => 'booked',
'>=APPOINTMENT_TIME' => \Bitrix\Main\Type\DateTime::createFromTimestamp($in2h->getTimestamp()),
'<=APPOINTMENT_TIME' => \Bitrix\Main\Type\DateTime::createFromTimestamp($in24h->getTimestamp()),
'REMINDER_24H_SENT' => 'N',
],
]);
while ($row = $appointments->fetch()) {
SmsService::send($row['PATIENT_PHONE'],
"Reminder of your appointment on " . date('d.m.Y H:i', strtotime($row['APPOINTMENT_TIME']))
);
AppointmentTable::update($row['ID'], ['REMINDER_24H_SENT' => 'Y']);
}
return __FUNCTION__ . '();';
}
Handling MIS Errors
The MIS may be unavailable (maintenance, server issues). Our strategy: if the MIS is unreachable, we save the request in the local_mis_pending_appointments table with status pending, display to the patient "Appointment accepted, we will contact you for confirmation." An agent tries to send pending records to the MIS every 5 minutes. After repeated failures, the record is marked manual — an operator contacts the patient. We implement this mechanism in every project and guarantee zero loss of requests.
How to Guarantee Zero Lost Requests?
If the MIS is unavailable, the request is saved in local_mis_pending_appointments table with status pending. An agent retries every 5 minutes. After 10 failed attempts, status changes to manual, and an operator contacts the patient. This scheme works in all projects and eliminates request loss.
What's Included in the Work
- Analysis of the specific MIS API documentation and selection of scenario
- Development of a PHP API client with error handling and retries
- Schedule caching with invalidation on booking
- Custom online booking component on the site (tailored to clinic design)
- Appointment table in Bitrix with status synchronization
- SMS/email notification setup (confirmation + reminders)
- Organization of a pending queue for requests when MIS is unavailable
- Load and fault tolerance testing
- Operational documentation and administrator training
How We Integrate MIS in 5 Steps
- MIS API analysis and scenario agreement (1–2 weeks).
- Client API development and backup storage (3–6 weeks).
- Booking component integration on the site (1–2 weeks).
- Notification and error queue setup (1 week).
- Load testing and staff training (1–2 weeks).
Timelines: from 5 to 14 weeks depending on complexity. Integration costs start at $5,000; typical projects run $5,000–$15,000. Clinics save up to 30% of administrative time and eliminate manual data entry errors. Order integration with zero loss guarantee — our certified specialists with 10 years of experience will select the right solution.
| Stage | Duration |
|---|---|
| Analysis and design | 1–2 weeks |
| Development and testing | 3–6 weeks |
| Implementation and training | 1–2 weeks |
| Warranty support | 1 month after launch |
Get a free consultation and project estimate — we will choose the optimal integration scenario and suggest timelines.







