Setting Up API Versioning for 1C-Bitrix
API versioning is a mechanism that allows you to make changes to an API without breaking existing integrations. A client using version v1 continues to work even after v2 is released with a changed response structure.
Why Versioning Is Needed
Without versioning, any change to the API response structure breaks clients: rename the price field to base_price — all integrations stop working. With versioning: in v1 price remains, in v2 base_price appears. Clients migrate to v2 at their own pace.
Versioning Strategies
URL versioning — the most common and transparent approach:
/api/v1/products
/api/v2/products
Implementation in Bitrix through routing in /local/php_interface/init.php or via a separate front controller.
Via header:
GET /api/products
Accept: application/vnd.myapi.v2+json
Less visible, but harder to debug — version is not shown in the URL.
Via query parameter:
GET /api/products?version=2
Easier to implement, but considered less "correct".
For Bitrix API, URL versioning is recommended — transparent, easily tested, clear to clients.
File Structure
/local/
api/
v1/
controllers/
ProductController.php
OrderController.php
routes.php
v2/
controllers/
ProductController.php ← modified version
routes.php
index.php ← version router
Version Router
// /local/api/index.php
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
preg_match('#^/api/(v\d+)/(.*)#', $path, $matches);
$version = $matches[1] ?? 'v1';
$endpoint = $matches[2] ?? '';
$routeFile = __DIR__ . "/{$version}/routes.php";
if (!file_exists($routeFile)) {
http_response_code(404);
echo json_encode(['error' => 'API version not found']);
exit;
}
require_once $routeFile;
Inheritance Between Versions
Version v2 is not rewritten from scratch — it inherits from v1 and overrides only what has changed:
// v2/controllers/ProductController.php
class ProductControllerV2 extends ProductControllerV1
{
public function index(): array
{
$products = parent::index();
// Modified structure: added field, renamed
return array_map(function ($product) {
$product['base_price'] = $product['price'];
unset($product['price']);
return $product;
}, $products);
}
}
This minimizes code duplication.
Version Lifecycle
| Status | Description |
|---|---|
| Current | Actual, recommended for new clients |
| Deprecated | Obsolete, works, but warning in response header |
| Sunset | Disabled in X months, announced in advance |
| Retired | Disabled, returns 410 Gone |
When accessing a deprecated version, a header is added:
header('Deprecation: true');
header('Sunset: Sat, 01 Jan 2026 00:00:00 GMT');
header('Link: </api/v2/products>; rel="successor-version"');
Version Information Storage
List of versions with their status — in configuration:
return [
'v1' => ['status' => 'deprecated', 'sunset' => '2026-01-01'],
'v2' => ['status' => 'current'],
];
The router reads the configuration and adds the necessary headers automatically.
Setting up versioning for an existing API with two versions — 1-2 days.







