Интеграция 1С-Битрикс с PIM-системой Salsify

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Предлагаемые услуги
Показано 1 из 1 услугВсе 1626 услуг
Интеграция 1С-Битрикс с PIM-системой Salsify
Средняя
~1-2 недели
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Разработка на базе Битрикс, Битрикс24, 1С для компании Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    747
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    976

Интеграция 1С-Битрикс с PIM-системой Salsify

Salsify — американская SaaS PIM-платформа, ориентированная на крупный e-commerce и мультиканальные продажи. Используется преимущественно брендами и дистрибьюторами, которые управляют тысячами SKU с синдикацией на маркетплейсы (Amazon, Walmart, Target). Если на Битрикс перенесён западный бренд или партнёрство предполагает использование Salsify как источника данных — интеграция строится через Salsify REST API.

Salsify API: основные эндпоинты

Salsify предоставляет REST API с токен-аутентификацией:

Base URL: https://app.salsify.com/api/v1/orgs/{org_id}/
Authorization: Bearer {api_key}

Ключевые эндпоинты:

GET products                    — список продуктов с атрибутами
GET products/{product_id}       — конкретный продукт
GET products?filter[updated_at][gte]={timestamp}  — изменённые с даты
GET property_groups             — группы атрибутов (аналог разделов свойств)
GET assets?filter[product_id]={id}  — медиафайлы продукта
GET digital_assets/{id}/download    — скачать файл

Salsify использует плоскую структуру атрибутов: каждый атрибут — пара «имя» : «значение», где имя может быть произвольным UUID или строкой. Перед маппингом нужно получить справочник атрибутов:

GET properties — возвращает все атрибуты организации с ID, name, data_type

Клиент Salsify

class SalsifyClient
{
    private string $baseUrl;
    private string $apiKey;

    public function __construct(string $orgId, string $apiKey)
    {
        $this->baseUrl = "https://app.salsify.com/api/v1/orgs/{$orgId}/";
        $this->apiKey  = $apiKey;
    }

    private function request(string $endpoint, array $params = []): array
    {
        $http = new \Bitrix\Main\Web\HttpClient();
        $http->setHeader('Authorization', 'Bearer ' . $this->apiKey);
        $http->setHeader('Content-Type', 'application/json');

        $url = $this->baseUrl . $endpoint;
        if ($params) {
            $url .= '?' . http_build_query($params);
        }

        $response = $http->get($url);
        return json_decode($response, true) ?? [];
    }

    public function getProducts(int $page = 1, int $perPage = 100, ?string $updatedAfter = null): array
    {
        $params = ['page' => $page, 'per_page' => $perPage];
        if ($updatedAfter) {
            $params['filter[updated_at][gte]'] = $updatedAfter;
        }
        return $this->request('products', $params);
    }

    public function getProperties(): array
    {
        return $this->request('properties');
    }

    public function downloadAsset(string $assetId): string
    {
        $http = new \Bitrix\Main\Web\HttpClient();
        $http->setHeader('Authorization', 'Bearer ' . $this->apiKey);
        return $http->get($this->baseUrl . 'digital_assets/' . $assetId . '/download');
    }
}

Маппинг атрибутов Salsify

Атрибуты Salsify идентифицируются по salsify:id (UUID) или по name. Конфигурация маппинга:

// /local/config/salsify-mapping.php
// 'salsify_property_id_or_name' => ['target' => 'bitrix_field', 'type' => 'field|prop']
return [
    'Product Name'              => ['target' => 'NAME',          'type' => 'field'],
    'Long Description'          => ['target' => 'DETAIL_TEXT',   'type' => 'field'],
    'Short Description'         => ['target' => 'PREVIEW_TEXT',  'type' => 'field'],
    'Brand'                     => ['target' => 'BRAND',         'type' => 'prop'],
    'Net Weight (kg)'           => ['target' => 'WEIGHT',        'type' => 'prop'],
    'Color'                     => ['target' => 'COLOR',         'type' => 'prop'],
    'Country of Origin'         => ['target' => 'COUNTRY_ORIGIN','type' => 'prop'],
    'GTIN'                      => ['target' => 'CML2_BAR_CODE', 'type' => 'prop'],
    'Manufacturer SKU'          => ['target' => 'CML2_ARTICLE',  'type' => 'prop'],
];

Синхронизация

function syncSalsifyAgent(): string
{
    $lastSync = \Bitrix\Main\Config\Option::get('salsify_sync', 'last_run', '');
    $client   = new SalsifyClient(SALSIFY_ORG_ID, SALSIFY_API_KEY);
    $mapping  = include '/local/config/salsify-mapping.php';

    $page    = 1;
    $newSync = date('c');

    do {
        $response = $client->getProducts($page, 100, $lastSync ?: null);
        $products = $response['products'] ?? [];

        foreach ($products as $product) {
            importSalsifyProduct($product, $mapping, $client);
        }

        $page++;
        $meta = $response['meta'] ?? [];
    } while (($meta['current_page'] ?? 1) < ($meta['total_pages'] ?? 1));

    \Bitrix\Main\Config\Option::set('salsify_sync', 'last_run', $newSync);
    return __FUNCTION__ . '();';
}

function importSalsifyProduct(array $product, array $mapping, SalsifyClient $client): void
{
    $attributes = $product['attributes'] ?? [];
    $sku        = $product['salsify:id'];

    // Получаем значения атрибутов
    $getValue = static function (array $attrs, string $key): mixed {
        return $attrs[$key] ?? null;
    };

    $fields = ['IBLOCK_ID' => CATALOG_IBLOCK_ID, 'ACTIVE' => 'Y'];
    $props  = [];

    foreach ($mapping as $salsifyKey => $config) {
        $value = $getValue($attributes, $salsifyKey);
        if ($value === null) continue;

        // Массивы преобразуем в строку через разделитель
        if (is_array($value)) {
            $value = implode(', ', $value);
        }

        if ($config['type'] === 'field') {
            $fields[$config['target']] = $value;
        } else {
            $props[$config['target']] = $value;
        }
    }

    $existing = CIBlockElement::GetList(
        [], ['IBLOCK_ID' => CATALOG_IBLOCK_ID, 'PROPERTY_CML2_ARTICLE' => $sku]
    )->Fetch();

    $el = new CIBlockElement();

    if ($existing) {
        $productId = $existing['ID'];
        $el->Update($productId, $fields);
    } else {
        $productId = $el->Add($fields);
    }

    if ($productId) {
        CIBlockElement::SetPropertyValuesEx($productId, CATALOG_IBLOCK_ID, $props);

        // Медиафайлы
        $primaryImage = $product['salsify:primary_image'] ?? null;
        if ($primaryImage) {
            importSalsifyAsset($productId, $primaryImage, $client);
        }
    }
}

Особенности Salsify

Сложные значения атрибутов. Salsify возвращает атрибуты как массив, где каждый элемент может быть скалярным значением, объектом или списком. Enum-атрибуты возвращают {"salsify:id": "...", "salsify:name": "Red"} — нужно извлекать salsify:name.

Цены. Salsify не является системой ценообразования. Цены, как правило, не синхронизируются из Salsify — они поступают из 1С. Проверьте с заказчиком, является ли Salsify источником цен или только контента.

Медиафайлы. Salsify хранит медиафайлы с CDN-ссылками. Можно не скачивать файлы, а хранить внешние URL в свойстве EXTERNAL_IMAGE_URL и подтягивать на лету через <img src="...">. Это экономит место на сервере Битрикс.

Webhook. Salsify поддерживает вебхуки при изменении продукта. Настраивается в Salsify → Integrations → Webhooks. URL обработчика принимает POST-запрос с product_id, затем запрашивает актуальные данные через API.

Сроки реализации

Объём Состав Срок
До 5 000 SKU, базовый контент Клиент + маппинг + агент 1–2 недели
10 000–100 000 SKU + медиа + вебхуки + обработка сложных атрибутов + оптимизация 3–4 недели
Мультирегиональный каталог (разные цены, контент по регионам) + логика каналов Salsify + мультисайт Битрикс 5–7 недель