Если вы когда-нибудь пытались связать CRM с сайтом, мобильным приложением или внутренней системой компании — вы знаете, что без API это превращается в боль. Ручной экспорт данных в Excel, копирование контактов по одному, постоянная рассинхронизация между системами... Знакомо?
REST API решает эти проблемы раз и навсегда. Вместо того чтобы вручную переносить данные, вы пишете код, который делает это автоматически. Новая заявка с сайта? Она мгновенно появляется в CRM. Менеджер закрыл сделку? Бухгалтерия сразу получает уведомление. Красота!
В этой статье я покажу конкретные примеры кода для работы с CRM через API. Никакой воды — только рабочие сниппеты на Python, JavaScript и общие принципы, которые пригодятся при интеграции с любой CRM-системой.
Любая современная CRM предоставляет стандартный набор эндпоинтов для работы с основными сущностями. Вот что обычно доступно «из коробки»:
На практике 80% интеграций сводятся к двум операциям: создать контакт/сделку при получении заявки и обновить статус при изменении в другой системе. Остальные эндпоинты — для более сложных сценариев вроде построения кастомных дашбордов или полной двусторонней синхронизации.
Первое, с чем сталкивается любой разработчик при работе с API — аутентификация. И тут важно выбрать правильный подход с самого начала, иначе потом придётся переделывать.
Независимо от выбранного метода, токен передаётся в заголовке запроса:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Совет из практики: храните API-ключи в переменных окружения, а не в коде. Один случайный коммит в публичный репозиторий — и ваш ключ уже на GitHub, сканируемый ботами. Поверьте, такое случается чаще, чем хотелось бы.
Полная документация, Swagger UI, примеры кода для всех эндпоинтов.
Получить доступ к APIДопустим, у вас есть форма обратной связи на сайте. Пользователь оставляет заявку — и вам нужно автоматически создать контакт в CRM. Вот как это делается на Python:
import requests
import os
# Ключ берём из переменных окружения, не хардкодим!
api_key = os.environ.get('CRM_API_KEY')
url = "https://api.crm-ai.ru/v1/contacts"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
# Данные из формы на сайте
data = {
"name": "Иван Петров",
"email": "ivan@example.com",
"phone": "+7 701 123-45-67",
"company": "ТОО Ромашка",
"source": "website_form", # откуда пришёл контакт
"tags": ["новый", "сайт"]
}
response = requests.post(url, json=data, headers=headers)
if response.status_code == 201:
contact = response.json()
print(f"Контакт создан, ID: {contact['id']}")
else:
print(f"Ошибка: {response.status_code} - {response.text}")
Обратите внимание: мы добавили поле source — это поможет потом в аналитике понять, откуда приходят лиды. Мелочь, но через полгода скажете спасибо.
Теперь представим другую задачу: нужно показать менеджеру его сделки в работе прямо в корпоративном портале. Для этого используем GET-запрос с параметрами фильтрации:
// Функция для получения сделок с фильтрами
async function getDeals(managerId, status = 'in_progress') {
const params = new URLSearchParams({
manager_id: managerId,
status: status,
limit: 50,
sort: '-updated_at' // минус означает сортировку по убыванию
});
const response = await fetch(
`https://api.crm-ai.ru/v1/deals?${params}`,
{
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.CRM_API_KEY}`,
'Content-Type': 'application/json'
}
}
);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
const data = await response.json();
// Возвращаем и сами сделки, и информацию о пагинации
return {
deals: data.items,
total: data.total,
hasMore: data.has_next_page
};
}
// Использование
const { deals, total } = await getDeals('manager_123');
console.log(`Найдено ${total} сделок в работе`);
Заметьте, что мы сразу обрабатываем ошибки и возвращаем информацию о пагинации. В реальных проектах это критично — никто не хочет загружать 10 000 сделок одним запросом.
API — это не волшебная палочка. Запросы падают, токены протухают, сервера иногда лежат. Хорошая новость: HTTP-коды ошибок стандартизированы, и по ним сразу понятно, что произошло.
Важно: всегда логируйте тело ответа при ошибках. Фраза «API вернул 400» ничего не говорит, а вот {"error": "email", "message": "Invalid email format"} — совсем другое дело.
Любой уважающий себя API ограничивает количество запросов. Это защита и для сервера, и для вас — случайный бесконечный цикл не положит всю систему.
Типичные лимиты выглядят примерно так:
Чтобы отслеживать лимиты, API возвращает специальные заголовки в каждом ответе:
X-RateLimit-Limit: 100 // ваш лимит
X-RateLimit-Remaining: 73 // сколько осталось
X-RateLimit-Reset: 1679012400 // когда счётчик сбросится (Unix timestamp)
Если всё-таки получили 429, не паникуйте. Правильный паттерн — exponential backoff: подождать 1 секунду, повторить. Если опять 429 — подождать 2 секунды, потом 4, 8 и так далее. Вот простая реализация:
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status !== 429) {
return response;
}
// Ждём с экспоненциальной задержкой
const delay = Math.pow(2, attempt) * 1000;
console.log(`Rate limited, waiting ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
throw new Error('Max retries exceeded');
}
Перед тем как деплоить интеграцию, пробегитесь по этому списку. Поверьте, лучше потратить 10 минут сейчас, чем ночь на дебаг в продакшене:
REST API — это мост между CRM и остальными системами вашего бизнеса. Да, первая интеграция всегда вызывает вопросы: как авторизоваться, что делать с ошибками, не забанят ли за частые запросы. Но стоит один раз разобраться — и следующие интеграции пишутся уже на автомате.
Главное помнить три вещи:
Если что-то пошло не так — не стесняйтесь писать в поддержку. Хороший вопрос с примером запроса и ответа решается в разы быстрее, чем «у меня ничего не работает».
Наша команда поможет настроить API-интеграцию под ваши задачи — от простой синхронизации контактов до сложных сценариев с несколькими системами.
Получить консультациюЕсли хотите глубже погрузиться в тему интеграций, вот несколько статей из нашего блога: