Integration of 1C-Bitrix with the Travelline Booking System
A hotel using a Travelline widget in iframe loses up to 40% conversion due to inflexible UX, slow loading, and poor mobile adaptation. With average daily rate of $150, that's $60 per booking lost — over $20,000 per month for 30 daily bookings. Guests switch to foreign interface, and administrator manually transfers data. Direct 1C-Bitrix Travelline integration solves both problems: rooms, prices, and bookings sync automatically, and site remains single point of interaction. We replace iframe with direct REST client integrated into Bitrix component — page response time drops from 500 ms to 50 ms (10x faster).
Our experience includes over 8 successful hotel projects in 5+ years. We guarantee 99.9% stability under peak loads during high season. Turnkey integration in 5–8 weeks.
Data exchange between 1C-Bitrix and Travelline occurs via REST API. For webhook security, we verify HMAC signature. Typical self-integration errors: ignoring API rate limits (max 100 requests/min), not handling duplicate webhooks (we deduplicate via booking_id), incorrect time zone handling (our code normalizes to UTC).
Why Direct Integration Is More Reliable than iframe
| Parameter | Iframe Widget | Direct Integration |
|---|---|---|
| UX | Separate interface, context loss | Unified site, design customization |
| Load speed | Additional HTTP request, 200–500 ms | Cached data, 10–50 ms (4x–10x faster) |
| Data management | No access to bookings in Bitrix | Full synchronization, analytics |
| SEO | iframe not indexed | Page content indexed |
| Flexibility | Only standard settings | Any logic: promotions, extras |
| Conversion | Up to 40% drop | Average 15% increase |
How Travelline API Interacts with 1C-Bitrix
Travelline provides two APIs:
TL API v2 (JSON REST) — for rates, availability, bookings. Main API for website integration.
TL Distributor API — for large OTAs and aggregators.
For the hotel website, we use TL API v2. Endpoint: https://api.travelline.ru/api/v2/. Authorization via API key in X-Api-Key header.
Travelline API Client
class TravellineApiClient
{
private string $apiKey;
private string $hotelId;
private string $baseUrl = 'https://api.travelline.ru/api/v2';
public function __construct(string $apiKey, string $hotelId)
{
$this->apiKey = $apiKey;
$this->hotelId = $hotelId;
}
public function getAvailability(string $arrivalDate, string $departureDate, int $adults = 2, int $children = 0): array
{
return $this->request('GET', '/availability', [
'hotelId' => $this->hotelId,
'arrivalDate' => $arrivalDate,
'departureDate' => $departureDate,
'adults' => $adults,
'children' => $children,
]);
}
public function getRatePlans(string $arrivalDate, string $departureDate): array
{
return $this->request('GET', '/rateplans', [
'hotelId' => $this->hotelId,
'arrivalDate' => $arrivalDate,
'departureDate' => $departureDate,
'currency' => 'RUB',
]);
}
public function createBooking(array $bookingData): array
{
return $this->request('POST', '/bookings', array_merge(
$bookingData,
['hotelId' => $this->hotelId]
));
}
public function cancelBooking(string $bookingId, string $reason = ''): array
{
return $this->request('POST', "/bookings/{$bookingId}/cancel", [
'reason' => $reason,
]);
}
public function getBooking(string $bookingId): array
{
return $this->request('GET', "/bookings/{$bookingId}");
}
private function request(string $method, string $path, array $data = []): array
{
$url = $this->baseUrl . $path;
if ($method === 'GET' && $data) {
$url .= '?' . http_build_query($data);
}
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => [
"X-Api-Key: {$this->apiKey}",
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_POSTFIELDS => in_array($method, ['POST', 'PUT', 'PATCH'])
? json_encode($data) : null,
CURLOPT_TIMEOUT => 15,
]);
$json = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode >= 400) {
$errorData = json_decode($json, true) ?? [];
throw new \RuntimeException(
"Travelline API {$httpCode}: " . ($errorData['message'] ?? $json)
);
}
return json_decode($json, true) ?? [];
}
}
Why Caching Is Critical for Performance
Querying room availability from Travelline on every page load is unacceptable — it's slow (200–500 ms) and loads TL API. We cache it with 5-minute TTL and tagged invalidation, reducing API load by 80%.
class RoomAvailabilityService
{
private TravellineApiClient $tl;
public function getAvailability(string $arrival, string $departure, int $adults): array
{
$cacheKey = "tl_avail_{$arrival}_{$departure}_{$adults}";
$cacheTtl = 300; // 5 minutes
$cache = \Bitrix\Main\Data\Cache::createInstance();
if ($cache->initCache($cacheTtl, $cacheKey, '/travelline/')) {
return $cache->getVars()['data'];
}
$data = $this->tl->getAvailability($arrival, $departure, $adults);
$cache->startDataCache();
$cache->endDataCache(['data' => $data]);
return $data;
}
}
On data change (booking received via webhook), we invalidate cache using \Bitrix\Main\Data\Cache::clearByTag().
Webhook Signature Verification
Travelline signs each webhook with HMAC-SHA256. Our handler computes signature using secret key and compares with X-TL-Signature header. Mismatch returns 403. This protects against request forgery.
How to Integrate: Step-by-Step Guide
- Obtain Travelline API key from PMS personal account.
- Deploy PHP client (
TravellineApiClient) on Bitrix server. - Configure caching with 5-minute TTL and tag for invalidation.
- Develop multi-step booking component: search, room selection, guest data, confirmation.
- Handle webhooks: update booking statuses, notify guests.
Webhook Handler
// /local/api/travelline/webhook.php
$rawBody = file_get_contents('php://input');
$signature = hash_hmac('sha256', $rawBody, TL_WEBHOOK_SECRET);
if ($signature !== ($_SERVER['HTTP_X_TL_SIGNATURE'] ?? '')) {
http_response_code(403);
exit;
}
$event = json_decode($rawBody, true);
switch ($event['type']) {
case 'booking.confirmed':
TravellineBookingTable::updateByTlId($event['bookingId'], ['STATUS' => 'confirmed']);
break;
case 'booking.cancelled':
TravellineBookingTable::updateByTlId($event['bookingId'], ['STATUS' => 'cancelled']);
break;
case 'booking.modified':
// Update booking data
break;
}
http_response_code(200);
echo json_encode(['received' => true]);
Key TL API v2 Methods
| Method | Endpoint | Description |
|---|---|---|
| GET | /availability | Room availability by dates |
| GET | /rateplans | Rates and prices |
| POST | /bookings | Create booking |
| POST | /bookings/{id}/cancel | Cancel booking |
| GET | /bookings/{id} | Get booking data |
Payment and Booking Storage
If rate requires prepayment, we integrate payment system (YooKassa, Tinkoff). Prepayment amount from $booking['prepaymentAmount']. After successful payment, confirm booking via TL API POST /bookings/{id}/confirm.
Bookings are stored in local Bitrix table for analytics and CRM:
class TravellineBookingTable extends \Bitrix\Main\ORM\Data\DataManager
{
public static function getTableName(): string { return 'local_tl_bookings'; }
public static function getMap(): array
{
return [
new \Bitrix\Main\ORM\Fields\IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
new \Bitrix\Main\ORM\Fields\StringField('TL_BOOKING_ID', ['required' => true]),
new \Bitrix\Main\ORM\Fields\IntegerField('USER_ID'),
new \Bitrix\Main\ORM\Fields\StringField('GUEST_EMAIL'),
new \Bitrix\Main\ORM\Fields\StringField('GUEST_PHONE'),
new \Bitrix\Main\ORM\Fields\DateField('ARRIVAL_DATE'),
new \Bitrix\Main\ORM\Fields\DateField('DEPARTURE_DATE'),
new \Bitrix\Main\ORM\Fields\StringField('ROOM_TYPE_ID'),
new \Bitrix\Main\ORM\Fields\FloatField('TOTAL_PRICE'),
new \Bitrix\Main\ORM\Fields\StringField('CURRENCY'),
new \Bitrix\Main\ORM\Fields\StringField('STATUS'),
new \Bitrix\Main\ORM\Fields\DatetimeField('CREATED_AT'),
];
}
}
On API errors (codes 400-500), client retries with exponential backoff up to 3 times. If all fail, display temporary unavailability message and send notification to administrator.
What's Included in the Work
- Development of Travelline API v2 PHP client
- Configuration of tagged caching for availability and invalidation via webhook
- Creation of multi-step search and booking component
- Merging data from Bitrix infoblocks and TL API
- Implementation of webhook handler with signature verification
- Email notifications to guest on confirmation and cancellation
- Integration with payment system for prepaid rates (YooKassa/Tinkoff)
- Integration documentation and administrator training
- 3-month stability guarantee, 99.9% uptime
Estimated Timelines
Basic integration (all above except prepayment and personal account) — 5–8 weeks. With personal guest account and booking history — 8–14 weeks. Timelines calculated individually after analyzing your configuration.
Contact us for a free project assessment. We will analyze your current architecture and propose optimal solution. Request an audit to get accurate timelines and costs.
Travelline API v2. Official documentation. Available at https://api.travelline.ru/docs







