Integrating 1C-Bitrix with EMIAS
EMIAS (Unified Medical Information and Analytical System) is Moscow's state healthcare platform used by municipal polyclinics and hospitals. Integration with EMIAS allows a medical institution's website (or Moscow's Gosuslugi portal) to display real physician schedules and accept online appointments directly into the system, bypassing the reception desk.
Working with EMIAS means interacting with a government system: it requires an agreement with the Moscow Department of Health, certification, and the issuance of access certificates. Technical integration is built on EMIAS SOAP or REST web services.
Accessing the EMIAS API
Obtaining EMIAS API access is an administrative process:
- Submit a request to the Moscow Department of Information Technologies (DIT)
- Sign an information interaction agreement
- Issue a certificate for mutual TLS (mTLS)
- Obtain a test environment and documentation
The EMIAS API uses WCF (Windows Communication Foundation) or REST depending on the version and module. For physician schedule management — the ScheduleService service.
SOAP Client for EMIAS
If EMIAS provides a WSDL:
class EmiasClient
{
private \SoapClient $client;
private string $certPath;
private string $certPassword;
public function __construct(string $wsdlUrl, string $certPath, string $certPassword)
{
$this->certPath = $certPath;
$this->certPassword = $certPassword;
// EMIAS requires mTLS — client certificate
$context = stream_context_create([
'ssl' => [
'local_cert' => $certPath,
'passphrase' => $certPassword,
'verify_peer' => true,
'verify_peer_name' => true,
'cafile' => '/etc/ssl/certs/emias-ca.crt',
],
]);
$this->client = new \SoapClient($wsdlUrl, [
'soap_version' => SOAP_1_2,
'encoding' => 'UTF-8',
'trace' => false,
'exceptions' => true,
'stream_context' => $context,
]);
}
public function getDoctorSchedule(string $lpuCode, int $doctorId, \DateTime $date): array
{
try {
$result = $this->client->GetSchedule([
'lpuCode' => $lpuCode,
'doctorId' => $doctorId,
'dateFrom' => $date->format('Y-m-d'),
'dateTo' => $date->format('Y-m-d'),
]);
return $this->parseScheduleResult($result);
} catch (\SoapFault $e) {
\Bitrix\Main\Diag\Debug::writeToFile(
"EMIAS SOAP fault: {$e->faultcode} — {$e->faultstring}",
'',
'/local/logs/emias.log'
);
throw new \RuntimeException("EMIAS error: {$e->faultstring}");
}
}
public function createAppointment(array $params): string
{
// Returns the EMIAS appointmentId
$result = $this->client->CreateAppointment([
'lpuCode' => $params['lpu_code'],
'doctorId' => $params['doctor_id'],
'slotId' => $params['slot_id'],
'patient' => [
'lastName' => $params['last_name'],
'firstName' => $params['first_name'],
'middleName' => $params['middle_name'] ?? '',
'birthDate' => $params['birth_date'], // DD.MM.YYYY
'snils' => $params['snils'], // Required for EMIAS
'oms' => $params['oms_policy'], // Compulsory health insurance policy
],
]);
return (string)$result->AppointmentId;
}
}
SNILS (national insurance number) and compulsory health insurance policy are required fields for EMIAS appointments. This is a key difference from commercial MIS systems, where a phone number is sufficient.
Patient Verification via Gosuslugi
Since EMIAS requires SNILS, integrating with Gosuslugi (ESIA) for patient authentication is a logical next step. The patient authenticates via Gosuslugi → the system retrieves their SNILS and ESIA data → passes it to EMIAS.
class GosuslugiEsiaService
{
// ESIA OAuth 2.0
private string $clientId; // System mnemonic in ESIA
private string $certPath; // IS certificate for signing requests
public function getAuthUrl(string $state): string
{
$timestamp = date('Y.m.d H:i:s O');
$scope = 'openid fullname snils medical';
// ESIA requires a signed request
$clientSecret = $this->signRequest(implode('', [
$scope, $timestamp, $this->clientId, $state
]));
return 'https://esia.gosuslugi.ru/aas/oauth2/ac?' . http_build_query([
'client_id' => $this->clientId,
'client_secret' => $clientSecret,
'redirect_uri' => SITE_SERVER_NAME . '/esia/callback/',
'scope' => $scope,
'response_type' => 'code',
'state' => $state,
'timestamp' => $timestamp,
'access_type' => 'online',
]);
}
private function signRequest(string $data): string
{
// Sign via openssl with the IS certificate
$pkcs7 = '';
openssl_pkcs7_sign(
tempnam(sys_get_temp_dir(), 'esia_'),
tempnam(sys_get_temp_dir(), 'esia_out_'),
file_get_contents($this->certPath),
['', ''],
[],
PKCS7_DETACHED | PKCS7_NOATTR
);
return base64_encode($pkcs7);
}
}
ESIA integration is a separate large-scale project with system certification requirements.
Schedule Caching and Synchronisation
Making direct EMIAS requests every time the schedule is displayed on the website is unacceptable from both a performance and EMIAS rate-limit perspective. The schedule is synchronised to a local table every 5–15 minutes:
class EmiasSyncAgent
{
public function syncSchedule(): string
{
$doctors = $this->getActiveDoctors(); // list of physicians from 1C-Bitrix
$dateRange = [
'from' => date('Y-m-d'),
'to' => date('Y-m-d', strtotime('+30 days')),
];
foreach ($doctors as $doctor) {
try {
$schedule = $this->emiasClient->getDoctorSchedule(
$doctor['LPU_CODE'],
$doctor['EMIAS_DOCTOR_ID'],
new \DateTime($dateRange['from'])
);
$this->upsertSlots($doctor['ID'], $schedule);
} catch (\RuntimeException $e) {
// Log the error without interrupting the loop for other physicians
\CEventLog::Add(['SEVERITY' => 'WARNING', 'DESCRIPTION' => $e->getMessage()]);
}
}
return __FUNCTION__ . '();';
}
}
Slots are stored in local_emias_slots: DOCTOR_ID, SLOT_DATE, SLOT_TIME, EMIAS_SLOT_ID, IS_FREE. The website reads slots from the local table rather than directly from EMIAS.
Concurrent Booking Conflicts
A user selects a 15:00 slot → begins filling in the form → another user books the same slot via the EMIAS portal. Solution:
- When the form is opened — "soft" slot reservation (flag in the local table)
- The reservation holds for 5 minutes
- On final form submission — the appointment is sent to the EMIAS API
- If EMIAS returns a "slot taken" error — display the nearest available slots
Scope of Work
- Obtaining EMIAS API access (administrative process, not development)
- mTLS setup, client certificate configuration
- EMIAS SOAP client, schedule parsing
- Schedule synchronisation to local table (agent)
- Appointment component with SNILS/health insurance policy form
- ESIA integration for authentication (optional, separate project)
- Concurrent booking conflict handling
Timeline: administrative procedures (access, agreement) — 1–3 months. Technical development after access is granted — 6–12 weeks.







