Как получить список контактов из amoCRM в 1С, если их больше 500?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При интеграции платформы 1С с облачной CRM-системой amoCRM разработчики часто сталкиваются с необходимостью выгрузки больших массивов данных. Одной из базовых задач является получение полного списка контактов. Однако стандартные методы API накладывают жесткие ограничения на количество элементов, возвращаемых за один HTTP-запрос. Если попытаться получить все контакты напрямую, система вернет лишь начальную порцию данных.

В данной статье мы подробно разберем, как обойти это ограничение, проанализируем типичные ошибки разработчиков на примере обсуждения с форума, а также рассмотрим современный и правильный способ реализации постраничной навигации (пагинации) в 1С для актуальной версии amoCRM API v4.

Анализируем типичную ошибку: как работает limit_offset в старом API v2

Обратимся к ситуации, описанной в ветке форума. Разработчик пытался использовать устаревший метод API v2 /private/api/v2/json/contacts/list и столкнулся с системным ограничением в 500 элементов. В ходе обсуждения был предложен правильный путь решения — использование параметров limit_rows (размер порции) и limit_offset (сдвиг выборки).

Однако автор темы допустил критическую ошибку в логике, предположив следующее: если limit_rows не может быть больше 500, то и limit_offset должен принимать значения строго от 1 до 500. Проанализируем, почему этот вывод неверен.

Параметр limit_rows определяет, сколько элементов вернет сервер за один раз (размер страницы). А параметр limit_offset указывает, с какого по счету элемента (начиная с нуля) нужно начать выборку. Таким образом, смещение может принимать абсолютно любые значения, кратные размеру страницы.

Выясним причину на простом примере. Предположим, у нас в базе amoCRM содержится 1500 контактов. Чтобы выгрузить их все с шагом в 500 элементов, нам необходимо выполнить три последовательных запроса в цикле:

  1. Первый запрос: устанавливаем limit_rows = 500 и limit_offset = 0. Сервер возвращает контакты с 1 по 500.
  2. Второй запрос: устанавливаем limit_rows = 500 и limit_offset = 500. Сервер возвращает контакты с 501 по 1000.
  3. Третий запрос: устанавливаем limit_rows = 500 и limit_offset = 1000. Сервер возвращает контакты с 1001 по 1500.

Этот цикл должен продолжаться до тех пор, пока сервер не вернет пустой массив данных, что будет означать окончание списка контактов.

Переход на API v4 и авторизацию OAuth 2.0

Важно учитывать, что код из примера на форуме использует устаревший протокол авторизации по ключам USER_LOGIN и USER_HASH, а также устаревшую ветку API v2. На сегодняшний день поддержка старых версий API полностью прекращена разработчиками amoCRM. Авторизация теперь осуществляется по протоколу OAuth 2.0 с использованием токенов доступа (access_token), передаваемых в заголовках HTTP-запроса.

В актуальной версии API v4 механизм постраничной навигации претерпел существенные изменения:

  1. Максимальное количество возвращаемых сущностей за один запрос снижено со 500 до 250 элементов.
  2. Вместо параметров limit_rows и limit_offset теперь используются более интуитивные параметры limit (количество элементов на страницу) и page (номер страницы).
  3. Ответы сервера теперь формируются в формате HAL JSON, содержащем специальный объект _links, который значительно упрощает переход по страницам.

Посмотрим, как выглядит структура ссылки на следующую страницу в формате HAL JSON, возвращаемом сервером amoCRM:


{
  "_links": {
    "self": {
      "href": "https://example.amocrm.ru/api/v4/contacts?limit=250&page=1"
    },
    "next": {
      "href": "https://example.amocrm.ru/api/v4/contacts?limit=250&page=2"
    }
  },
  "_embedded": {
    "contacts": [
      { "id": 123, "name": "Иван Иванов" }
    ]
  }
}

Благодаря наличию объекта _links.next.href, нам больше не нужно вручную рассчитывать смещения или номера страниц в коде 1С. Достаточно парсить полученный JSON-ответ, извлекать адрес следующей страницы и выполнять по нему запрос. Если свойство next отсутствует в структуре _links, это означает, что мы достигли конца списка.

Реализация постраничной выгрузки контактов в 1С

Рассмотрим подробнее программный код на языке 1С для получения всех контактов с использованием API v4. Мы будем выполнять запросы в цикле, проверять код состояния ответа и анализировать структуру JSON для перехода на следующую страницу.


&НаСервере
Процедура ПолучитьВсеКонтактыИзAmoCRM()

    // Настройки подключения к вашему аккаунту amoCRM
    АдресРесурса = "example.amocrm.ru"; // Укажите субдомен вашей организации
    ТокенДоступа = "ВАШ_ACCESS_TOKEN";  // Актуальный OAuth access_token
    
    // Начальный путь для запроса первой страницы
    ТекущийПуть = "/api/v4/contacts?limit=250&page=1";
    
    Соединение = Новый HTTPСоединение(АдресРесурса, 443,,,,, Новый ЗащищенноеСоединениеOpenSSL());
    
    СистематическийЦикл = Истина;
    НомерСтраницы = 1;
    
    Пока СистематическийЦикл Цикл
        
        Запрос = Новый HTTPЗапрос(ТекущийПуть);
        Запрос.Заголовки.Вставить("Authorization", "Bearer " + ТокенДоступа);
        Запрос.Заголовки.Вставить("Content-Type", "application/json");
        
        Попытка
            Ответ = Соединение.Получить(Запрос);
        Исключение
            ЗаписьЖурналаРегистрации("amoCRM.Интеграция", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
            Прервать;
        КонецПопытки;
        
        КодСостояния = Ответ.КодСостояния;
        
        // Если контакты закончились, сервер возвращает код HTTP 204 No Content
        Если КодСостояния = 204 Тогда
            ЗаписьЖурналаРегистрации("amoCRM.Интеграция", УровеньЖурналаРегистрации.Информация,,, "Все контакты успешно загружены.");
            Прервать;
        ИначеЕсли КодСостояния <> 200 Тогда
            ЗаписьЖурналаРегистрации("amoCRM.Интеграция", УровеньЖурналаРегистрации.Предупреждение,,, "Неожиданный ответ сервера: " + КодСостояния);
            Прервать;
        КонецЕсли;
        
        // Чтение и парсинг полученных данных
        ТелоОтвета = Ответ.ПолучитьТелоКакСтроку();
        ЧтениеJSON = Новый ЧтениеJSON;
        ЧтениеJSON.УстановитьСтроку(ТелоОтвета);
        ДанныеОтвета = ПрочитатьJSON(ЧтениеJSON);
        ЧтениеJSON.Закрыть();
        
        // Обрабатываем контакты из текущей выборки
        Если ДанныеОтвета.Свойство("_embedded") И ДанныеОтвета._embedded.Свойство("contacts") Тогда
            МассивКонтактов = ДанныеОтвета._embedded.contacts;
            Для Каждого Контакт Из МассивКонтактов Цикл
                // Здесь выполняется логика обработки конкретного контакта
                ИмяКонтакта = Контакт.name;
                IDКонтакта = Контакт.id;
            КонецЦикла;
        КонецЕсли;
        
        // Проверяем наличие следующей страницы через объект _links
        ЕстьСледующаяСтраница = Ложь;
        Если ДанныеОтвета.Свойство("_links") И ДанныеОтвета._links.Свойство("next") Тогда
            ПолныйАдресСледующей = ДанныеОтвета._links.next.href;
            
            // Извлекаем относительный путь из полного URL
            ПозицияПути = Найти(ПолныйАдресСледующей, "/api/v4/");
            Если ПозицияПути > 0 Тогда
                ТекущийПуть = Сред(ПолныйАдресСледующей, ПозицияПути);
                ЕстьСледующаяСтраница = Истина;
            КонецЕсли;
        КонецЕсли;
        
        // Если следующей страницы нет - завершаем цикл выгрузки
        Если Не ЕстьСледующаяСтраница Тогда
            Прервать;
        КонецЕсли;
        
        // Применяем задержку для обхода лимитов на количество запросов в секунду
        ПриостановитьВыполнениеПотока(0.2); 
        
        НомерСтраницы = НомерСтраницы + 1;
        
    КонецЦикла;

КонецПроцедуры

Для корректного разбора структуры JSON мы используем встроенные в платформу 1С объекты ЧтениеJSON и функцию ПрочитатьJSON(). Это позволяет транслировать строки JSON в стандартное дерево значений, соответствия и структуры платформы 1С, обеспечивая обращение к параметрам через точку (например, ДанныеОтвета._links.next.href).

Важно: обход технических лимитов запросов (Rate Limits)

При написании подобных циклических алгоритмов в 1С крайне важно учитывать системные ограничения платформы amoCRM на частоту запросов. В amoCRM установлено ограничение: не более 7 запросов в секунду для одной интеграции.

Если база содержит тысячи контактов, и цикл в 1С будет выполняться без пауз, вы мгновенно исчерпаете этот лимит. В ответ на ваши запросы сервер начнет возвращать ошибку с кодом 429 Too Many Requests, а сессия интеграции может быть временно заблокирована.

Чтобы избежать этой проблемы, мы принудительно замедляем выполнение цикла 1С между запросами страниц. В коде выше мы применили процедуру ПриостановитьВыполнениеПотока(). Посмотрим, как ее можно реализовать в 1С:


Процедура ПриостановитьВыполнениеПотока(Секунды)
    
    // Для платформы 1С v8.3.15 и выше доступен штатный метод приостановки
    Попытка
        ПриостановитьВыполнение(Секунды);
    Исключение
        // Альтернативный метод задержки для старых версий платформы через Wscript.Shell
        Попытка
            WshShell = Новый COMОбъект("Wscript.Shell");
            WshShell.Run("ping -n " + Строка(Секунды + 1) + " 127.0.0.1", 0, Истина);
        Исключение
            // Резервный пустой цикл, если COM-объект недоступен
            НачалоПаузы = ТекущаяДата();
            Пока ТекущаяДата() - НачалоПаузы < Секунды Цикл
                // Холостой ход
            КонецЦикла;
        КонецПопытки;
    КонецПопытки;
    
КонецПроцедуры

Оптимальный интервал задержки между запросами страниц составляет около 150–200 миллисекунд (0.2 секунды). Это гарантирует стабильную загрузку тысяч контактов без риска блокировки сессии со стороны amoCRM.

Используя предложенные методики пагинации и контроля лимитов, мы можем построить надежный и отказоустойчивый мост интеграции между 1С и amoCRM, обеспечивающий корректную синхронизацию списков любой длины.

← На главную