A shipper comes to the site with one task: find out the shipping cost, place an order, track the cargo. If the calculator doesn't work, tracking shows no status, and for a repeat shipment they have to fill in 12 fields again—the client leaves for a competitor with a proper personal cabinet. We develop logistics company websites on 1С-Битрикс, and 10+ years of experience allow us to avoid these mistakes. Contact us to discuss your project architecture.
Битрикс can assemble all this, but the architecture must be tailored to logistics specifics from day one. We don't just configure infoblocks—we design a system that will withstand thousands of requests to the calculator, integration with 1С, and provide reliable tracking with a B2B cabinet. Let's break down specific solutions.
How is the service catalog structured?
A logistics company offers not one product but a matrix of services: FTL (full truckload), LTL (less than truckload), warehousing, customs clearance, last-mile delivery. Each type has its own parameters—weight limits, dimensions, temperature range, geography.
Data structure:
- Infoblock "Services"—sections: Road transport, Sea, Rail, Air, Warehouse services, Customs
- Highload block "Transport types"—reference: tarp, refrigerator, container 20', container 40', isothermal. Fields: UF_NAME, UF_CAPACITY_KG, UF_VOLUME_M3, UF_PHOTO, UF_DESCRIPTION
- Highload block "Routes"—city-city pairs linked to transport types. Fields: UF_FROM_CITY, UF_TO_CITY, UF_TRANSPORT_TYPE, UF_TRANSIT_DAYS, UF_ACTIVE
- Highload block "Cargo restrictions"—max weight, dimensions, prohibited categories per transport type
Each service in the infoblock contains:
| Property | Type | Purpose |
|---|---|---|
| SERVICE_TYPE | L (list) | FTL / LTL / Warehousing / Customs / LastMile |
| TRANSPORT_TYPES | S:Highload (multi) | Link to allowed transport types |
| ROUTE_DIRECTIONS | S:Highload (multi) | Available directions |
| MAX_WEIGHT | N | Max cargo weight, kg |
| MAX_VOLUME | N | Max volume, m³ |
| TEMPERATURE_MODE | L | Normal / Refrigerator / Freezer |
| INSURANCE_AVAILABLE | L | Yes / No |
| CUSTOMS_INCLUDED | L | Yes / No |
For SEO, pages like "[transport type] + [route]" are critical: "Road transport Moscow — Novosibirsk", "LTL from China". These pages are generated from the service infoblock and route Highload block through a custom component. The URL is built using the pattern /uslugi/{service-code}/{from}-{to}/, SEF is configured via CIBlockElement::GetList with filtering by properties ROUTE_FROM and ROUTE_TO.
How to implement a shipping cost calculator?
The calculator is the reason 70% of visitors come to a logistics company's website. Not a "leave a request, we'll call back" form, but a real calculation: from where, to where, what are we shipping, how much does it cost. If the calculator doesn't give a price—the visitor doesn't become a lead.
The calculator architecture consists of three layers.
Layer 1—frontend: multi-step form. Step 1: from → to (autocomplete cities via AJAX, data from Highload block "Cities" or external API—Yandex.Geocoder). Step 2: cargo parameters—weight, volume (L×W×H), number of pieces, packaging type, temperature mode. Step 3: additional options—insurance, customs clearance, door-to-door delivery. Step 4: result—cost, time, available transport types.
The form is implemented as a React component or vanilla JS with step-by-step navigation. Each step has AJAX validation on the server. City autocomplete is a separate endpoint /api/cities/suggest/?q=Moscow, which searches b_hlbd_cities (Highload block) via DataManager::getList() with filter ['%UF_NAME' => $query].
Layer 2—distance calculation. Tariffs depend on distance. Two approaches:
Approach A—pre-calculated distance matrix in Highload block DistanceMatrix. Fields: UF_FROM_CITY_ID, UF_TO_CITY_ID, UF_DISTANCE_KM, UF_TRANSIT_HOURS. With 500 cities, 250K records—quite feasible. Pro: instant response, no dependency on external APIs. Con: needs recalculation when adding cities.
Approach B—real-time calculation via external API. Yandex.Routing API (router.route()) or Google Distance Matrix API. Request: two points → distance in km + travel time. Cache result in Highload block: if city pair already calculated—use cache, otherwise—API request + save. Cache TTL—30 days.
// Getting distance with caching
class DistanceService
{
public static function getDistance(int $fromCityId, int $toCityId): array
{
// Check cache in Highload block
$cached = DistanceMatrixTable::getList([
'filter' => [
'UF_FROM_CITY_ID' => $fromCityId,
'UF_TO_CITY_ID' => $toCityId,
'>UF_CACHED_AT' => date('Y-m-d', strtotime('-30 days'))
]
])->fetch();
if ($cached) {
return [
'distance_km' => $cached['UF_DISTANCE_KM'],
'transit_hours' => $cached['UF_TRANSIT_HOURS']
];
}
// Request to Yandex.Routing API
$result = YandexRoutingClient::route(
Cities::getCoordinates($fromCityId),
Cities::getCoordinates($toCityId)
);
// Save to cache
DistanceMatrixTable::add([
'UF_FROM_CITY_ID' => $fromCityId,
'UF_TO_CITY_ID' => $toCityId,
'UF_DISTANCE_KM' => $result['distance'],
'UF_TRANSIT_HOURS' => $result['duration'],
'UF_CACHED_AT' => new DateTime()
]);
return $result;
}
}
Implementation details of distance matrix caching
Caching is done with a TTL of 30 days. On request, the record date is checked. If no record exists or it's outdated, an API request to Yandex.Routing is made. The result is saved in the DistanceMatrix Highload block. To update all routes once a month, an agent runs that recalculates outdated records.
Layer 3—tariff calculation. Tariffs are stored in a Highload block Tariffs with the structure:
| Field | Type | Description |
|---|---|---|
| UF_SERVICE_TYPE | list | FTL / LTL / Express |
| UF_TRANSPORT_TYPE | link | Transport type |
| UF_DISTANCE_FROM | number | Range start, km |
| UF_DISTANCE_TO | number | Range end, km |
| UF_RATE_PER_KM | number | Rate per km |
| UF_MIN_RATE | number | Minimum cost |
| UF_WEIGHT_COEFF | number | Overage coefficient |
| UF_VOLUME_COEFF | number | Volume coefficient |
Calculation formula for LTL: max(distance_km * rate_per_km, min_rate) * weight_coeff * volume_coeff + insurance + customs_fee. For FTL—simpler: fixed rate per km × distance, no weight coefficients (full truck).
The manager updates tariffs through the administrative interface of the Highload block—without involving a developer. This is critical: tariffs change weekly, and if updating prices requires a deploy—the system is dead.
The calculator result is returned as a JSON response:
{
"variants": [
{
"transport": "Tarp 20t",
"service": "FTL",
"price": 45000,
"currency": "RUB",
"transit_days": 3,
"distance_km": 1800
},
{
"transport": "LTL",
"service": "LTL",
"price": 12500,
"currency": "RUB",
"transit_days": 7,
"distance_km": 1800
}
]
}
Below the result is a "Place order" button, which transfers all calculation parameters to the order form. The user doesn't need to re-enter data.
Why is cargo tracking critical for customer retention?
Tracking is the second reason clients return to the site. A tracking number input field on the homepage, result—a chain of statuses with dates and current location on a map.
Data source—1С:TMS or 1С:Logistics. Integration via REST API documentation: 1С sends status updates via POST /rest/logistics.shipment.updateStatus with fields tracking_number, status_code, location, timestamp. Битрикс stores statuses in a Highload block ShipmentStatuses.
On the frontend—AJAX request by tracking number. The response contains an array of statuses (received, at warehouse, in transit, at customs, delivered) and the last known location coordinates for display on a map via Yandex.Maps.
Real-time updates—through polling every 60 seconds or WebSocket if traffic volume justifies the complexity.
How to set up a B2B cabinet for a logistics company?
A personal cabinet for corporate clients is what distinguishes a serious logistics company from a "business card site with a calculator". This is not just an order history, but a full-fledged working tool for a logistician.
Authorization and roles. The client company registers as a legal entity. Inside the company—several users with different roles. Implementation via Битрикс user groups (CGroup) and custom fields:
- Company administrator—sees all orders, manages users, downloads documents, sees finances
- Logistician—creates orders, tracks statuses, downloads TTN and CMR
- Accountant—access only to documents: invoices, acts, invoices
User to company binding—via custom field UF_COMPANY_ID in b_user. Access check—middleware in init.php that on every request to /personal/ checks the user group and UF_COMPANY_ID.
Cabinet functionality:
Order history—list of all company shipments with filtering by date, status, direction. Data from Highload block Orders with fields: UF_ORDER_NUMBER, UF_COMPANY_ID, UF_FROM_CITY, UF_TO_CITY, UF_STATUS, UF_CARGO_DESCRIPTION, UF_WEIGHT, UF_VOLUME, UF_PRICE, UF_CREATED_AT. Pagination via bitrix:system.pagenavigation, filtering—AJAX.
Document workflow—each order contains a set of documents: TTN, CMR, invoice, packing list, insurance policy. Files stored as a multiple property of type "File" linked to the order. Downloading—via a custom controller that checks document belonging to the user's company before serving the file. No direct links to /upload/—only authorized access.
// Document access check
class DocumentController extends Controller
{
public function download(int $orderId, int $fileId): Response
{
$user = $GLOBALS['USER'];
$order = OrdersTable::getById($orderId)->fetch();
if ($order['UF_COMPANY_ID'] !== $user->getUfCompanyId()) {
throw new AccessDeniedException();
}
$file = CFile::GetFileArray($fileId);
return new BinaryFileResponse($file['SRC']);
}
}
Repeat shipment templates. Regular clients ship the same cargo along the same routes. The logistician saves an order as a template; next time—selects the template, changes the date, confirms. Templates—a separate Highload block ShipmentTemplates with fields duplicating the order structure, plus UF_TEMPLATE_NAME and UF_COMPANY_ID.
Financial section—settlement balance, issued invoices, payment history. Data synchronized from 1С via REST API on schedule (every 15 minutes) or by event.
Integration with 1С:TMS
Order synchronization between the site and 1С:TMS (or 1С:Vehicle Management) is bidirectional:
- Site → 1С: a new order from the site is sent to 1С via REST API. The endpoint on the 1С side accepts JSON with order parameters and creates a "Transport request" document
- 1С → Site: status change in 1С triggers a webhook on Битрикс. The handler updates UF_STATUS in the Orders Highload block and sends an email/SMS to the client
Exchange format—JSON over HTTP REST. XML exchange via CommerceML is redundant for logistics—it's a trade format, not for transport.
Coverage map and fleet
Interactive map—Yandex.Maps with a custom layer. Markers of warehouses and hubs from Highload block Warehouses (fields: UF_NAME, UF_ADDRESS, UF_COORDINATES, UF_TYPE, UF_PHOTO). Route lines between hubs—ymaps.Polyline with data from the route Highload block. Click on a hub—balloon with address, operating hours, available services.
Fleet—infoblock with transport types. Vehicle card: photo, load capacity, body volume, type (tarp, refrigerator, container carrier). Output via bitrix:news.list with custom template—grid of cards with characteristic icons.
API for partners
REST API for integration with partner systems: freight forwarders, marketplaces, client ERP systems. Endpoints:
-
POST /api/v1/orders/create—create order -
GET /api/v1/orders/{id}/status—order status -
GET /api/v1/tracking/{number}—tracking -
POST /api/v1/calculate—cost calculation
Authorization—API key in the X-Api-Key header. Keys generated in the admin panel, linked to the partner company. Rate limiting—100 requests per minute via middleware.
Stages and timelines
| Scale | Timeline |
|---|---|
| Business card site with calculator, up to 10 routes | 4-6 weeks |
| Corporate site with cabinet, tracking, 1С integration | 10-16 weeks |
| Platform with partner API, B2B portal, full automation | 16-24 weeks |
Timelines do not include configuring exchange on the 1С side—that's a separate project by a 1С developer, running in parallel.
What's included in development
- Documentation: architecture description, data schema, tariff update instructions
- Access: source code, admin panel access, repository
- Training: training managers to use the admin panel (up to 4 hours)
- Support: warranty support 1 month after launch
Our experience—10+ years in 1С-Битрикс development and 50+ projects for logistics companies. Using Битрикс, we cut site launch time by 2x compared to custom solutions. Get a consultation or order the development of a logistics company website on 1С-Битрикс—we'll calculate cost and timeline within 1 business day.







