1C Integration with OpenCart
Synchronizing catalog, stock, and orders between 1C and OpenCart is standard task for online stores with accounting system. Data must flow both ways: products from 1C to OpenCart, orders from OpenCart to 1C.
Integration Approaches
CommerceML (1C standard) — 1C can generate XML files in CommerceML 2 format and exchange them with the website via HTTP. Most compatible method.
REST API — 1C Enterprise 8.3 supports HTTP services. OpenCart provides REST API. More flexible but requires programming on both sides.
Direct Database Connection — not recommended in production but used for one-time migrations.
CommerceML Integration
Protocol: 1C sends POST requests to special script on website. OpenCart must have handler /index.php?route=api/1c/....
Install module: 1C-Bitrix Exchange (open source) or ocStore Exchange 1C.
Configuration in 1C (Data Exchange with Website):
Website URL: https://shop.ru/index.php?route=api/1c
User: OpenCart API user
Password: ****
Frequency: every 15 minutes (stock), every hour (full catalog)
Custom CommerceML Handler
// catalog/controller/api/exchange1c.php
class ControllerApi1cExchange extends Controller {
private function authenticate(): bool {
$token = $this->request->get['token'] ?? $this->request->server['HTTP_X_API_TOKEN'] ?? '';
return hash_equals($this->config->get('api_1c_token'), $token);
}
public function catalog(): void {
if (!$this->authenticate()) {
$this->response->setOutput('failure=Unauthorized');
return;
}
$mode = $this->request->get['mode'] ?? '';
match ($mode) {
'checkauth' => $this->checkAuth(),
'init' => $this->init(),
'file' => $this->receiveFile(),
'import' => $this->import(),
default => $this->response->setOutput('failure=Unknown mode'),
};
}
private function import(): void {
$filename = $this->request->get['filename'] ?? '';
$filePath = DIR_UPLOAD . 'exchange1c/' . basename($filename);
if (!file_exists($filePath)) {
$this->response->setOutput('failure=File not found');
return;
}
$xml = simplexml_load_file($filePath);
$this->processProducts($xml);
$this->response->setOutput('success=Import completed');
}
private function processProducts(\SimpleXMLElement $xml): void {
foreach ($xml->Catalog->Goods->Good as $product) {
$sku = (string)$product->Article;
$name = (string)$product->Name;
$price = (float)$product->PricePerUnit;
$existingId = $this->getProductIdBySku($sku);
if ($existingId) {
$this->model_catalog_product->editProduct($existingId, [
'price' => $price,
'quantity' => (int)$product->Stock,
]);
} else {
$this->model_catalog_product->addProduct([
'sku' => $sku,
'model' => $sku,
'name' => ['ru' => $name],
'price' => $price,
'quantity' => (int)$product->Stock,
'status' => 1,
]);
}
}
}
}
Stock Synchronization (Fast Mode)
For frequent stock updates (every 5–15 minutes) — separate lightweight endpoint:
// POST /api/1c/stock
// Body: JSON [{sku: "ART-001", qty: 15}, ...]
public function updateStock(): void {
$items = json_decode($this->request->post['data'], true);
$updated = 0;
foreach ($items as $item) {
$productId = $this->getProductIdBySku($item['sku']);
if ($productId) {
$this->db->query("UPDATE " . DB_PREFIX . "product SET quantity = '" . (int)$item['qty'] . "'
WHERE product_id = '" . (int)$productId . "'");
$updated++;
}
}
$this->response->addHeader('Content-Type: application/json');
$this->response->setOutput(json_encode(['updated' => $updated]));
}
Exporting Orders to 1C
// GET /api/1c/orders?from=2024-01-01&status=2
public function getOrders(): void {
$dateFrom = $this->request->get['from'] ?? date('Y-m-d', strtotime('-1 day'));
$statusId = (int)($this->request->get['status'] ?? 2); // 2 = Processing
$orders = $this->model_sale_order->getOrders([
'filter_date_added' => $dateFrom,
'filter_order_status_id' => $statusId,
]);
$result = [];
foreach ($orders as $order) {
$products = $this->model_sale_order->getOrderProducts($order['order_id']);
$result[] = [
'id' => $order['order_id'],
'date' => $order['date_added'],
'total' => $order['total'],
'customer' => $order['firstname'] . ' ' . $order['lastname'],
'phone' => $order['telephone'],
'address' => $order['shipping_address_1'],
'products' => array_map(fn($p) => [
'sku' => $p['model'],
'name' => $p['name'],
'qty' => $p['quantity'],
'price' => $p['price'],
], $products),
];
}
$this->response->addHeader('Content-Type: application/json');
$this->response->setOutput(json_encode(['orders' => $result]));
}
Error Handling and Queue
For reliability — asynchronous queue. If 1C unavailable, changes are queued:
// Queue table
CREATE TABLE oc_1c_queue (
id INT AUTO_INCREMENT PRIMARY KEY,
type ENUM('product', 'stock', 'order') NOT NULL,
payload JSON NOT NULL,
status ENUM('pending', 'processing', 'done', 'failed') DEFAULT 'pending',
attempts INT DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
processed_at DATETIME NULL
);
Timelines
Basic integration (catalog + stock via CommerceML) — 5–7 days. Bidirectional integration with orders and queue — 10–14 days.







