Integration of 1C-Bitrix with EMIAS

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.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1177
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • 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
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

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:

  1. Submit a request to the Moscow Department of Information Technologies (DIT)
  2. Sign an information interaction agreement
  3. Issue a certificate for mutual TLS (mTLS)
  4. 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:

  1. When the form is opened — "soft" slot reservation (flag in the local table)
  2. The reservation holds for 5 minutes
  3. On final form submission — the appointment is sent to the EMIAS API
  4. 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.