1C-Bitrix Integration with Diadoc (Kontur) EDI System
Diadoc by SKB Kontur is the largest EDI operator in Russia. Legally significant invoices, shipping documents, acceptance acts, and UPD (universal transfer documents) are signed with a qualified electronic signature (QES) and transmitted through Diadoc without paper duplicates. When an online store or B2B platform sends hundreds of documents per month, manual work in the Diadoc web interface becomes untenable — integration with 1C-Bitrix is required to automatically create and send documents triggered by system events.
Integration Architecture
Diadoc provides a REST API (https://diadoc-api.kontur.ru/). Authorization is via a token issued by login/password or a QES certificate. Server-side integration uses token-based authorization.
Integration flow:
Bitrix (event: order paid)
→ PHP handler
→ XML document generation (UPD/Act)
→ POST /v1/organizations/{orgId}/messages (Diadoc API)
→ Diadoc delivers to counterparty
→ Diadoc webhook: signing status
→ Status update in Bitrix
Diadoc API Authorization
class DiadokClient
{
private string $apiKey;
private string $token;
private string $baseUrl = 'https://diadoc-api.kontur.ru';
public function __construct(string $apiKey, string $login, string $password)
{
$this->apiKey = $apiKey;
$this->token = $this->authenticate($login, $password);
}
private function authenticate(string $login, string $password): string
{
$response = $this->request('POST', '/V3/Authenticate', [
'login' => $login,
'password' => $password,
], false);
return $response; // returns a token string
}
public function request(string $method, string $path, array $data = [], bool $auth = true): mixed
{
$headers = ['DiadocAuth ddauth_api_client_id=' . $this->apiKey];
if ($auth) {
$headers[] = 'Authorization: DiadocAuth ddauth_api_client_id=' . $this->apiKey
. ', ddauth_token=' . $this->token;
}
// ... curl/Guzzle request
}
}
XML Document Generation
Diadoc accepts documents as XML conforming to the Federal Tax Service (FTS) standard. For UPD (universal transfer document) — the format follows FTS Order MMV-7-15/820.
class UPDGenerator
{
public function generateFromOrder(\Bitrix\Sale\Order $order): string
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$root = $dom->createElement('Файл');
$root->setAttribute('ИдФайл', $this->generateFileId($order));
$root->setAttribute('ВерсПрог', 'BitrixIntegration 1.0');
$root->setAttribute('ВерсФорм', '5.02');
// Participant information
$svUch = $dom->createElement('СвУчДокОбор');
$svSender = $dom->createElement('СвОЭДОтпр');
$svSender->setAttribute('НаимОрг', $this->senderName);
$svSender->setAttribute('ИННЮЛ', $this->senderInn);
$svSender->setAttribute('ИдЭДО', $this->senderEdoId);
$svUch->appendChild($svSender);
$root->appendChild($svUch);
// Document
$doc = $dom->createElement('Документ');
$doc->setAttribute('КНД', '1115125');
$doc->setAttribute('ФункцДок', 'ДОП'); // ДОП = transfer of work/service results
$doc->setAttribute('НомерДок', $order->getId());
$doc->setAttribute('ДатаДок', date('d.m.Y'));
$doc->setAttribute('Сумма', number_format($order->getPrice(), 2, '.', ''));
$doc->setAttribute('СумНал', $this->calculateVat($order));
// Line items (order positions)
$this->appendOrderItems($dom, $doc, $order);
$root->appendChild($doc);
$dom->appendChild($root);
return $dom->saveXML();
}
}
XML validation before submission is mandatory. The FTS publishes XSD schemas that must be used to verify document structure.
Sending a Document via the API
public function sendUPD(\Bitrix\Sale\Order $order, string $recipientOrgId): string
{
$xml = (new UPDGenerator())->generateFromOrder($order);
// Upload document
$uploadResult = $this->client->request('POST',
"/V3/PostMessagePatchDraft?boxId={$this->boxId}",
[
'FromBoxId' => $this->boxId,
'ToBoxId' => $recipientOrgId,
'DocumentAttachments' => [[
'SignedContent' => [
'Content' => base64_encode($xml),
'Signature' => $this->sign($xml), // QES signature
],
'TypeNamedId' => 'UniversalTransferDocument',
'Function' => 'ДОП',
'Version' => 'utd820_05_01_02_hyphen',
]],
]
);
return $uploadResult['MessageId'];
}
To sign documents with a QES on the server, a cryptographic provider is required — CryptoPro CSP or ViPNet CSP. Integration uses openssl_pkcs7_sign() with a certificate installed on the server.
Status Handling
Diadoc notifies about document status changes in two ways: polling (GET /V3/GetNewEvents) and webhooks (push notifications).
Polling for lower document volumes:
// Runs via cron every 5 minutes
public function syncDocumentStatuses(): void
{
$events = $this->client->request('GET',
"/V3/GetNewEvents?boxId={$this->boxId}&afterEventId={$this->lastEventId}"
);
foreach ($events['Events'] as $event) {
$docId = $event['DocumentInfo']['DocumentId'];
$status = $event['DocumentInfo']['DocflowStatus']['PrimaryStatus']['StatusText'];
$orderId = $this->getOrderIdByDocumentId($docId);
if ($orderId) {
$this->updateOrderStatus($orderId, $status);
}
$this->lastEventId = $event['EventId'];
}
}
Case Study: Automated EDI for a Wholesale Supplier
A cosmetics distributor, ~800 B2B orders per month. Each order required a UPD. An employee manually created documents in Diadoc — 20–30 minutes per order cumulatively per day.
What was automated:
-
When the order status changes to "Shipped" (
OnSaleStatusOrder) — automatic generation and submission of UPD to Diadoc. Counterparty details are taken from Bitrix order properties (INN, KPP, Diadoc BoxId). -
Counterparty directory: for a first order from a new legal entity — automatic BoxId lookup via
GET /V3/GetOrganizationsByInnKpp. If found — saved to a custom buyer field in Bitrix. -
When the counterparty signs the UPD — a Diadoc webhook changes the order status to "Documents signed". The manager sees the change in Bitrix without opening Diadoc.
-
Notification: if the counterparty rejects the document with a comment — the manager receives a Bitrix notification (
CEventLog::Add()) with the rejection reason.
| Metric | Before | After |
|---|---|---|
| Time spent on EDI processing | 20–30 min/day | < 2 min/day (exceptions only) |
| Errors in counterparty details | ~5% of documents | < 0.5% |
| Counterparty signing time | Not tracked | Monitored, average 1.8 days |
Document History Storage in Bitrix
A table for tracking all documents, created via D7:
class DiadokDocumentTable extends \Bitrix\Main\ORM\Data\DataManager
{
public static function getTableName(): string { return 'local_diadok_documents'; }
public static function getMap(): array
{
return [
new \Bitrix\Main\ORM\Fields\IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
new \Bitrix\Main\ORM\Fields\IntegerField('ORDER_ID'),
new \Bitrix\Main\ORM\Fields\StringField('DIADOK_MESSAGE_ID'),
new \Bitrix\Main\ORM\Fields\StringField('DOCUMENT_TYPE'), // UPD, ACT, INVOICE
new \Bitrix\Main\ORM\Fields\StringField('STATUS'), // sent, signed, rejected
new \Bitrix\Main\ORM\Fields\DatetimeField('CREATED_AT'),
new \Bitrix\Main\ORM\Fields\DatetimeField('SIGNED_AT'),
];
}
}
Scope of Work
- Diadoc account setup, obtaining API keys
- CryptoPro CSP installation on the server, loading the QES certificate
- PHP Diadoc API client development
- XML document generator (UPD, Acts) with XSD validation
- Bitrix event handlers (order status change)
- Status synchronization: polling or webhooks
- Document history storage, display within the Bitrix order view
Timeline: basic integration (UPD submission, status sync) — 3–5 weeks. Full integration with multiple document types, counterparty directory, and notifications — 6–10 weeks.







