Интеграция CRM-системы amoCRM с сайтом

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

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

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Интеграция CRM-системы amoCRM с сайтом
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1214
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    852
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    823
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    815

Интеграция CRM-системы amoCRM с сайтом

amoCRM ориентирована на отделы продаж: воронка, контакты, задачи, чаты. REST API покрывает все основные сущности. Аутентификация — только через OAuth 2.0 (не webhook-токены как в Битрикс24), что требует настройки приложения и хранения refresh-токена.

OAuth 2.0 для server-to-server

amoCRM использует Authorization Code flow с долгоживущим refresh-токеном (60 дней). Алгоритм:

  1. Создаём интеграцию в аккаунте amoCRM: Настройки → Интеграции → Создать интеграцию
  2. Получаем client_id, client_secret, redirect_uri
  3. Первичная авторизация — ручной шаг через браузер (генерация code)
  4. Обмен code на access + refresh токены — программно
  5. Автоматическое обновление access-токена через refresh
class AmoCrmTokenStorage {
    private const CACHE_KEY = 'amocrm_tokens';

    public function getAccessToken(): string {
        $tokens = Cache::get(self::CACHE_KEY);
        if (!$tokens || now()->gte($tokens['expires_at'])) {
            $tokens = $this->refreshTokens($tokens['refresh_token']);
        }
        return $tokens['access_token'];
    }

    private function refreshTokens(string $refreshToken): array {
        $response = Http::post(config('amocrm.base_url') . '/oauth2/access_token', [
            'client_id'     => config('amocrm.client_id'),
            'client_secret' => config('amocrm.client_secret'),
            'grant_type'    => 'refresh_token',
            'refresh_token' => $refreshToken,
            'redirect_uri'  => config('amocrm.redirect_uri'),
        ]);

        $data = $response->json();
        $tokens = [
            'access_token'  => $data['access_token'],
            'refresh_token' => $data['refresh_token'],
            'expires_at'    => now()->addSeconds($data['expires_in'] - 60),
        ];

        Cache::put(self::CACHE_KEY, $tokens, now()->addDays(60));
        // Также сохраняем в БД как резерв (cache может очиститься)
        DB::table('settings')->updateOrInsert(
            ['key' => 'amocrm_tokens'],
            ['value' => json_encode($tokens), 'updated_at' => now()]
        );

        return $tokens;
    }
}

API-клиент

class AmoCrmClient {
    private AmoCrmTokenStorage $tokenStorage;
    private string $baseUrl;

    public function __construct(AmoCrmTokenStorage $tokenStorage) {
        $this->tokenStorage = $tokenStorage;
        $this->baseUrl = rtrim(config('amocrm.base_url'), '/') . '/api/v4';
    }

    public function get(string $endpoint, array $params = []): array {
        return Http::withToken($this->tokenStorage->getAccessToken())
            ->timeout(15)
            ->get($this->baseUrl . $endpoint, $params)
            ->throw()
            ->json();
    }

    public function post(string $endpoint, array $data): array {
        return Http::withToken($this->tokenStorage->getAccessToken())
            ->timeout(15)
            ->post($this->baseUrl . $endpoint, $data)
            ->throw()
            ->json();
    }

    public function patch(string $endpoint, array $data): array {
        return Http::withToken($this->tokenStorage->getAccessToken())
            ->timeout(15)
            ->patch($this->baseUrl . $endpoint, $data)
            ->throw()
            ->json();
    }
}

Создание контакта и сделки

amoCRM строится на трёх основных сущностях: Contact, Lead (сделка), Company. Новый лид с сайта — это связка Contact + Lead:

class AmoCrmLeadService {
    public function createLeadFromForm(array $formData): array {
        $amo = app(AmoCrmClient::class);

        // Ищем существующий контакт по телефону
        $existing = $amo->get('/contacts', [
            'query' => $formData['phone'],
            'with'  => 'leads',
        ]);

        $contactId = null;
        if (!empty($existing['_embedded']['contacts'])) {
            $contactId = $existing['_embedded']['contacts'][0]['id'];
        }

        // Создаём контакт если не найден
        if (!$contactId) {
            $result    = $amo->post('/contacts', [[
                'name'             => $formData['name'],
                'custom_fields_values' => [
                    [
                        'field_code' => 'PHONE',
                        'values'     => [['value' => $formData['phone'], 'enum_code' => 'WORK']],
                    ],
                    [
                        'field_code' => 'EMAIL',
                        'values'     => [['value' => $formData['email'] ?? '', 'enum_code' => 'WORK']],
                    ],
                ],
            ]]);
            $contactId = $result['_embedded']['contacts'][0]['id'];
        }

        // Создаём сделку
        $pipelineId = config('amocrm.pipeline_id');
        $stageId    = config('amocrm.initial_stage_id');

        $leadResult = $amo->post('/leads', [[
            'name'        => 'Заявка с сайта: ' . $formData['name'],
            'pipeline_id' => $pipelineId,
            'status_id'   => $stageId,
            '_embedded'   => [
                'contacts' => [['id' => $contactId]],
            ],
            'custom_fields_values' => [
                [
                    'field_id' => config('amocrm.fields.source'),
                    'values'   => [['value' => $formData['source'] ?? 'Сайт']],
                ],
                [
                    'field_id' => config('amocrm.fields.utm_campaign'),
                    'values'   => [['value' => session('utm_campaign') ?? '']],
                ],
            ],
        ]]);

        $leadId = $leadResult['_embedded']['leads'][0]['id'];

        // Добавляем примечание
        $amo->post('/leads/' . $leadId . '/notes', [[
            'note_type' => 'common',
            'params'    => ['text' => 'Сообщение: ' . ($formData['message'] ?? '')],
        ]]);

        return ['lead_id' => $leadId, 'contact_id' => $contactId];
    }
}

Webhook от amoCRM

Настройка webhook в amoCRM: Настройки → Интеграции → Webhooks. При изменении сделки amoCRM шлёт POST:

// routes/api.php
Route::post('/webhooks/amocrm', [AmoCrmWebhookController::class, 'handle']);

class AmoCrmWebhookController extends Controller {
    public function handle(Request $request): Response {
        // amoCRM шлёт данные в form-encoded формате, не JSON!
        $data = $request->all();

        if (isset($data['leads']['status'])) {
            foreach ($data['leads']['status'] as $lead) {
                $this->syncLeadStatus($lead['id'], $lead['status_id']);
            }
        }

        if (isset($data['leads']['add'])) {
            // Новая сделка создана в amoCRM (не с сайта)
            foreach ($data['leads']['add'] as $lead) {
                Log::info('New lead in amoCRM', ['id' => $lead['id']]);
            }
        }

        return response('ok');
    }

    private function syncLeadStatus(int $leadId, int $statusId): void {
        $order = Order::where('amocrm_lead_id', $leadId)->first();
        if (!$order) return;

        $map = [
            config('amocrm.stages.won')        => 'completed',
            config('amocrm.stages.lost')       => 'cancelled',
            config('amocrm.stages.in_work')    => 'processing',
        ];

        if ($status = $map[$statusId] ?? null) {
            $order->update(['status' => $status]);
        }
    }
}

Пользовательские поля

amoCRM поддерживает кастомные поля для сделок и контактов. ID полей нужно получить через API и сохранить в конфиге:

// Получить список полей воронки
$fields = $amo->get('/leads/custom_fields');
foreach ($fields['_embedded']['custom_fields'] as $field) {
    echo $field['id'] . ' — ' . $field['name'] . PHP_EOL;
}

Затем в config/amocrm.php:

'fields' => [
    'source'       => 12345,
    'utm_source'   => 12346,
    'utm_campaign' => 12347,
    'order_number' => 12348,
],

Обновление сделки при оплате

add_action('order_paid', function(Order $order) {
    if (!$order->amocrm_lead_id) return;

    app(AmoCrmClient::class)->patch('/leads/' . $order->amocrm_lead_id, [
        'price'     => $order->total,
        'status_id' => config('amocrm.stages.won'),
        'custom_fields_values' => [
            [
                'field_id' => config('amocrm.fields.order_number'),
                'values'   => [['value' => $order->number]],
            ],
        ],
    ]);
});

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

OAuth-авторизация, базовая отправка лидов из форм, хранение токена: 1–2 дня. Полноценная интеграция: двусторонняя синхронизация статусов, webhook-обработчик, кастомные поля, UTM-метки: 3–4 дня. Синхронизация каталога, создание задач по событиям сайта, интеграция чата: плюс 2–3 дня.