Когда клиент просит подключить доставку СДЭК к сайту, боту или CRM, разговор всегда упирается в один и тот же вопрос: API СДЭК, где взять ключи доступа и как их не перепутать с логином от личного кабинета. На практике путаница возникает из-за того, что у СДЭК два разных контура с разными ключами, а вебхуки настраиваются не в интерфейсе, а отдельным запросом к API. Разберу по шагам, где искать client_id и client_secret, как получить токен и как подписаться на события по заказу, чтобы статусы доставки прилетали в CRM или Telegram-бот сами, без ручной проверки трек-номеров.
Где взять ключи API СДЭК: аккаунт и личный кабинет
Ключи выдаются не сразу после регистрации на сайте cdek.ru, а через отдельный личный кабинет интеграции на lk.cdek.ru. Обычному клиенту, который просто отправляет посылки через форму, эти ключи не нужны, они появляются только у тех, кто подключает СДЭК как способ доставки к своей системе.
Порядок такой:
- Регистрируетесь как юрлицо или ИП в личном кабинете СДЭК, заключаете договор на доставку (без действующего договора боевой доступ не откроют).
- В разделе «Интеграция» находите пункт «API» или пишете на integration@cdek.ru с просьбой выдать доступ к API v2.
- Получаете пару account_id (он же client_id) и secure_password (client_secret) для тестового контура, обычно это происходит в течение одного рабочего дня.
- Для боевого контура нужно отдельно запросить продакшн-ключи, приложив реквизиты и номер договора, ждать 1-3 рабочих дня.
Важный момент: client_secret показывается в кабинете один раз, дальше его можно только перевыпустить. Я всегда сразу кладу его в переменные окружения проекта (.env), а не в код, потому что это фактически пароль от вашего аккаунта в API.
Тестовый и боевой контур: чем отличаются ключи доступа
СДЭК держит две независимые площадки: тестовую (её ещё называют sandbox или интеграционной) и боевую. У них разные адреса, разные ключи и разные ограничения, и это первое, о чём забывают при переносе интеграции в продакшн.
| Параметр | Тестовый контур | Боевой контур |
|---|---|---|
| Базовый URL API | api.edu.cdek.ru/v2 | api.cdek.ru/v2 |
| Как получить ключи | По заявке, обычно за 1 день | Нужен действующий договор, 1-3 дня |
| Реальная отправка заказов | Нет, все заказы виртуальные | Да, создаются настоящие накладные |
| Вебхуки | Работают, можно тестировать все типы событий | Работают, события приходят по реальным заказам |
Я всегда пишу и отлаживаю интеграцию на тестовом контуре целиком, включая вебхуки, и только потом меняю базовый URL и пару ключей на боевые. Логика запросов у обоих контуров идентична, отличаются только адрес и учётка, так что после отладки достаточно поменять две переменные в конфиге.
Бесплатный материал
🎁 Полезный скрипт в подарок
Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.
Без спама. Отписка в 1 клик.
Получение токена и первый запрос к API СДЭК
Авторизация в API СДЭК v2 идёт по протоколу OAuth 2.0, схема client_credentials. Никакого логина и пароля от личного кабинета в запросах не участвует, только client_id и client_secret.
Запрос токена выглядит так:
curl -X POST 'https://api.edu.cdek.ru/v2/oauth/token?parameters' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=client_credentials&client_id=ВАШ_ACCOUNT_ID&client_secret=ВАШ_SECRET'
В ответ приходит access_token, тип bearer и срок жизни в секундах, обычно 3600. То есть токен нужно кэшировать и обновлять раз в час, а не запрашивать перед каждым вызовом API, СДЭК банит за избыточные запросы к оутентификации при высокой частоте.
Дальше токен передаётся в заголовке к любому методу, например при создании заказа или запросе стоимости доставки:
curl -X GET 'https://api.edu.cdek.ru/v2/orders/72753294-70e6-4160-9f38-9c72a1e0b8ba' \
-H 'Authorization: Bearer ВАШ_ACCESS_TOKEN'
Одна из частых ошибок на этом шаге, путать account_id с числовым идентификатором из старого API v1, у СДЭК до сих пор встречаются примеры кода в интернете под старую версию, а v1 отключена.
Настройка вебхуков СДЭК: типы событий, подписка и защита обработчика
Вебхуки в API СДЭК не включаются переключателем в интерфейсе, их регистрируют отдельным POST-запросом, указывая свой адрес обработчика и типы событий, на которые хотите подписаться.
Основные типы событий:
- ORDER_STATUS - смена статуса заказа (принят, в пути, вручён, возврат);
- PRINT_FORM - готовность печатной формы накладной;
- DOWNLOAD_PHOTO - фото подтверждения вручения;
- RECEIPT - готовность квитанции.
Подписка регистрируется так:
curl -X POST 'https://api.edu.cdek.ru/v2/webhooks' \
-H 'Authorization: Bearer ВАШ_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://example.com/cdek/webhook",
"type": "ORDER_STATUS"
}'
Если адрес обработчика недоступен по HTTPS или отвечает дольше нескольких секунд, СДЭК помечает подписку неактивной и перестаёт слать события, поэтому обработчик должен сразу отвечать 200 и уже потом заниматься логикой в фоне.
Второй момент, о котором часто забывают, доверие к входящим данным. Подписи у вебхука СДЭК нет, тело запроса ничем не заверено, и сверить его с секретом не получится. Защищаться приходится косвенно, и я делаю три вещи: принимаю событие на неочевидный адрес по HTTPS, а не на /cdek-webhook, подтверждаю событие обратным запросом к API СДЭК по uuid заказа и только после этого меняю статус у себя, и делаю обработчик идемпотентным, чтобы повторная доставка того же события не переписала заказ второй раз. На PHP при приёме события в WordPress или WooCommerce это выглядит так:
$payload = file_get_contents('php://input');
$data = json_decode($payload, true);
http_response_code(200);
$uuid = $data['uuid'] ?? '';
$key = 'cdek_event_' . hash('sha256', $payload);
if ($uuid === '' || get_transient($key)) {
exit;
}
set_transient($key, 1, DAY_IN_SECONDS);
$response = wp_remote_get('https://api.cdek.ru/v2/orders/' . $uuid, [
'headers' => ['Authorization' => 'Bearer ' . $access_token],
'timeout' => 10,
]);
$order = json_decode(wp_remote_retrieve_body($response), true);
Если вебхук нужен не для сайта, а для оповещения менеджеров, я обычно кидаю событие в Telegram-бота на aiogram, там же можно сразу отформатировать статус заказа человеческим текстом вместо технического кода СДЭК.
Интеграция СДЭК в Tilda, WordPress и n8n на практике
Tilda не умеет принимать вебхуки напрямую, у неё нет серверной части для этого, поэтому между СДЭК и Tilda всегда стоит промежуточный обработчик, свой скрипт на хостинге или сценарий в n8n, который получает вебхук, пересчитывает статус и записывает его в CRM или в свою таблицу заказов. Обратно в Tilda статус не записать: её API работает только на чтение, это семь GET-методов для выгрузки проектов и страниц, лимит 150 запросов в час и тариф Business.
На WooCommerce ситуация проще, обработчик вебхука ставится прямым PHP-эндпоинтом или плагином, и статус заказа СДЭК синхронизируется со статусом заказа в WooCommerce напрямую. Если в проекте уже подключена оплата через T‑Bank, оба вебхука, от эквайринга и от СДЭК, обычно обрабатываются одним контроллером с разными роутами, чтобы не плодить точки входа на сервере.
Когда писать отдельный бэкенд под один вебхук нецелесообразно, я собираю приём и маршрутизацию событий СДЭК в n8n: нода Webhook принимает запрос, следующая нода подтверждает событие запросом к API СДЭК, а дальше данные уходят в Google-таблицу, Telegram или CRM без единой строчки кода на сервере. Такую разработку интеграции с CRM и эквайрингом под задачу я обычно оцениваю от 40 000 ₽, если речь про комплексную связку СДЭК плюс оплата плюс CRM, а не про одну изолированную доработку скрипта.
Частые вопросы
Можно ли получить боевые ключи API СДЭК без договора?
Нет, боевой контур привязан к вашему юрлицу и действующему договору на доставку. Без договора доступен только тестовый контур, там ключи выдаются практически сразу, но заказы там виртуальные и в реальную доставку не уходят.
Почему вебхук от СДЭК не приходит на сервер?
Чаще всего проблема в трёх местах: адрес обработчика недоступен по HTTPS, сервер отвечает дольше нескольких секунд, из-за чего СДЭК считает подписку неудачной, или подписка вообще не была зарегистрирована запросом к /v2/webhooks, а не просто ожидалась по умолчанию.
Как долго живёт токен доступа к API СДЭК?
Access_token, полученный через /oauth/token, действует обычно 3600 секунд, то есть час. Дальше его нужно запросить заново по тем же client_id и client_secret, кэшировать токен и переиспользовать его на все запросы в течение этого часа, а не получать новый перед каждым вызовом.
Нужно ли хранить ключи СДЭК на своём сервере в России?
Да, если через интеграцию проходят персональные данные получателей (ФИО, адрес, телефон), хранить их и логи вебхуков стоит на серверах в РФ, а не в зарубежных таблицах или облачных сервисах, это требование 152-ФЗ о локализации персональных данных.