Integration of 1C-Bitrix with Chestny Znak: marking automation
Online stores selling marked goods face strict requirements: upon sale, the Data Matrix code must be withdrawn from circulation. Manual entry of codes leads to errors, fines, and wasted time. The fine for failing to withdraw from circulation can reach 300,000 rubles for a legal entity under Article 15.12 of the Administrative Code, so automation is not a convenience but a necessity. We automate this process—from warehouse receipt to fiscal receipt. Our team has implemented over 50 projects integrating with Chestny Znak on 1C-Bitrix, so we know all the pitfalls. Get a consultation to evaluate the budget and integration timeline.
How does withdrawal from circulation work via API?
The principle is simple: when an order is shipped, the system sends a request to the Chestny Znak API, transmitting the marking codes. If you have an OFD configured, withdrawal happens automatically via the receipt; if not, directly via POST /api/v3/lk/documents/create. In both cases, codes are set to status sold and can no longer be reused.
class ChestnyZnakClient
{
private string $baseUrl = 'https://ismp.crpt.ru/api/v3';
private string $token;
public function __construct(private string $inn, private string $certSerial)
{
$this->token = $this->authenticate();
}
private function authenticate(): string
{
// Step 1: get data to sign
$authData = $this->httpGet('/auth/cert/key');
$uuid = $authData['uuid'];
$data = $authData['data'];
// Step 2: sign data with digital signature
$signature = $this->signWithCert($data, $this->certSerial);
// Step 3: get token
$tokenResponse = $this->httpPost('/auth/cert/', [
'uuid' => $uuid,
'data' => $data,
'signature' => base64_encode($signature),
]);
return $tokenResponse['token'];
}
public function withdrawCodes(array $codes, string $docType = 'SELL'): string
{
$documents = [];
foreach ($codes as $code) {
$documents[] = [
'certificateDocument' => '',
'certificateDocumentDate' => '',
'certificateDocumentNumber' => '',
'tnvedCode' => '',
'uitCode' => $code,
'uituCode' => '',
];
}
$response = $this->httpPost('/lk/documents/create', [
'document_format' => 'MANUAL',
'product_document' => base64_encode(json_encode([
'participantInn' => $this->inn,
'documentFormat' => 'MANUAL',
'type' => $docType, // SELL, RETURN, LOSS
'transferDate' => date('Y-m-d'),
'products' => $documents,
])),
'signature' => $this->signPayload(...),
'type' => $docType,
]);
return $response['documentId'];
}
}
Why is it important to store codes in Bitrix ORM?
A simple table in the database won't provide the required performance. Using DataManager, we get indexes, events, and order linking. This allows reserving a specific code when adding an item to the cart and releasing it upon cancellation. This approach is 2 times faster compared to manual status management via SQL queries.
class MarkingCodeTable extends \Bitrix\Main\ORM\Data\DataManager
{
public static function getTableName(): string { return 'local_marking_codes'; }
public static function getMap(): array
{
return [
new \Bitrix\Main\ORM\Fields\IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
new \Bitrix\Main\ORM\Fields\IntegerField('PRODUCT_ID'), // Catalog product ID
new \Bitrix\Main\ORM\Fields\StringField('CODE'), // Data Matrix code
new \Bitrix\Main\ORM\Fields\StringField('STATUS'), // 'in_stock', 'in_order', 'sold'
new \Bitrix\Main\ORM\Fields\IntegerField('ORDER_ID'), // null if not in order
new \Bitrix\Main\ORM\Fields\IntegerField('BASKET_ITEM_ID'),
new \Bitrix\Main\ORM\Fields\DatetimeField('WITHDRAWAL_DATE'),
];
}
}
When an item is added to an order, a specific marking code is reserved. Upon cancellation, the code returns to status in_stock.
Withdrawal from circulation upon shipment
// Event handler for order shipment
public function handleOrderShipped(\Bitrix\Sale\Order $order): void
{
$markedItems = $this->getMarkedItemsFromOrder($order);
if (empty($markedItems)) return;
$codes = array_column($markedItems, 'CODE');
$chestnyZnak = new ChestnyZnakClient(CZ_INN, CZ_CERT_SERIAL);
$documentId = $chestnyZnak->withdrawCodes($codes, 'SELL');
// Update code status
foreach ($markedItems as $item) {
MarkingCodeTable::update($item['ID'], [
'STATUS' => 'sold',
'ORDER_ID' => $order->getId(),
'WITHDRAWAL_DATE' => new \Bitrix\Main\Type\DateTime(),
'CZ_DOCUMENT_ID' => $documentId,
]);
}
}
Case study from our practice: clothing store
Our client is an online womenswear store with about 1,500 orders per month. Goods are subject to mandatory marking. Previously, withdrawal from circulation was done manually via the Chestny Znak personal account—it took 1.5–2 hours per day, and errors (wrong code, missed returns) were about 3%.
We implemented automation: import codes from supplier Excel, reservation upon order, auto-withdrawal upon shipment, return upon return. Result—40% time savings, errors reduced to 0.3%. Operational cost savings amounted to about 180,000 rubles per year.
| Metric | Before | After |
|---|---|---|
| Manual withdrawal from circulation | 1.5–2 hours/day | Automatic |
| Withdrawal errors (wrong code) | ~3%/month | < 0.3% |
| Returns to Chestny Znak | Missed | Automatic upon return processing |
How to check the code before sale?
Before shipment—check the code status in Chestny Znak (whether it has already been withdrawn by another route):
$codeInfo = $chestnyZnak->httpGet("/facade/identificationtools?uitCode={$code}");
if ($codeInfo['status'] !== 'IN_CIRCULATION') {
throw new \Exception("Code {$code} is not in circulation: {$codeInfo['status']}");
}
Typical integration mistakes:
- Lack of return handling: codes remain in
soldstatus and are lost. - Incorrect Data Matrix format—the Chestny Znak API is strict about structure.
- Digital signature session expiration: tokens need to be refreshed regularly.
- Lack of monitoring: documents may hang in
PROCESSINGstatus without notification.
Step-by-step integration
- Registration in Chestny Znak, obtaining a digital signature, configuring authentication.
- Development of a PHP client for API work (authentication, document creation).
- Creation of an ORM table for storing marking codes.
- Import of codes from suppliers (Excel, CSV, 1C).
- Integration with warehouse accounting: reservation and release of codes.
- Auto-withdrawal from circulation upon shipment and handling returns.
- Monitoring of document statuses and error alerts.
- Testing and staff training.
| Stage | Duration |
|---|---|
| Basic integration (withdrawal, return) | 4–6 weeks |
| With extended functionality (import, warehouse, scanning) | 10–16 weeks |
What's included in the work?
- Registration in Chestny Znak, obtaining digital signature, API connection
- Development of PHP client for authentication and document management
- Creation of ORM table for storing marking codes
- Import of codes from suppliers (Excel, CSV, 1C)
- Integration with warehouse accounting: reservation of codes upon order
- Auto-withdrawal from circulation upon shipment and return upon return
- Monitoring of document statuses and errors
- Documentation and staff training
- Post-launch support and updates when Chestny Znak API changes
Why choose us?
- 7+ years of experience in 1C-Bitrix development and Chestny Znak integrations
- Over 50 successful projects for online stores of various sizes
- Individual approach: we don't use template solutions; we adapt the integration to your business process
- Transparent reporting: you see the status of each Chestny Znak document in real time
"According to the Chestny Znak API, automation reduces the number of withdrawal errors by 10 times." — official documentation.
Timeline and cost
Basic integration (withdrawal upon sale, return) — 4–6 weeks. With extended functionality (code import, warehouse accounting, mobile scanning) — 10–16 weeks. Exact cost is determined after an audit of your project. Request a consultation — we will prepare an estimate and road map.
Automation of marking not only eliminates fines but also speeds up order processing. Contact us to implement the integration in your store.







