Почему их постоянно путают?
Потому что оба — «длинные секретные строки из настроек». Но роли противоположные:
- API-ключ отвечает на вопрос «кто ко мне пришёл?» для ApiPay. Вы выставляете счёт → кладёте ключ в
X-API-Key→ мы понимаем, чья это организация. - Вебхук-секрет отвечает на тот же вопрос для вас. Мы присылаем вебхук об оплате → вы считаете HMAC от сырого тела запроса своим секретом → сверяете с заголовком
X-Webhook-Signature. Совпало — это точно ApiPay, а не злоумышленник, слепивший фейковый «paid».
Две зеркальные ошибки из практики поддержки:
- Подписывают исходящие запросы секретом (кладут его в
X-API-Keyили городят HMAC на POST /invoices) → получают401. Ваши запросы к API подписывать не нужно — только ключ в заголовке. - Проверяют вебхук API-ключом → подпись «не сходится» при идеально правильном коде. HMAC считается от вебхук-секрета. Код проверки на Node/Python/PHP — в «Как настроить вебхуки ApiPay».
Где взять API-ключ
Кабинет apipay.kz → Настройки → API-ключи → «Создать». Задаёте имя (уникально в пределах организации), опционально — webhook_url и срок действия. Полный ключ показывается только в этот момент — скопируйте в менеджер секретов/переменные окружения. Дальше в списке виден лишь key_hint — последние символы, чтобы отличать ключи друг от друга.
Нюанс, который экономит час отладки: ключ создаётся внутри организации. Нет организации — нет ключа (400 organization_required); ключ тестовой организации никогда не заработает с боевой — это разные организации с разными ключами.
Где взять вебхук-секрет (кнопка, которую «обычно не находят»)
Секрет генерируется на API-ключе и только после того, как у ключа указан webhook_url. Порядок строго такой:
- Откройте ключ в «Настройки → API-ключи».
- Впишите
webhook_url(публичный HTTPS) и сохраните. - Появится кнопка «Сгенерировать подпись» — нажмите. Это и есть вебхук-секрет; показывается один раз.
Пока URL не задан, кнопки нет — и это не баг: секрет нужен для проверки вебхуков, а без URL вебхуков не будет («нет вебхука — нечего валидировать»). Именно на этом шаге чаще всего «не могут найти секрет».
Когда ключи «внезапно» перестают работать
Все случаи ниже — документированное поведение, а не потеря данных:
- Перегенерация.
regenerate(ключ) иregenerate-secret(секрет) мгновенно убивают старое значение. Если интеграций несколько — обновите значение во всех местах сразу. - Партнёрская повторная выдача. Партнёрский эндпоинт
POST /api/partner/organizations/{id}/api-keyидемпотентен: повторный вызов (например, «на всякий случай» после привязки кассира) перегенерирует ключ той же записи и заменяет её вебхук-настройки — старый ключ мгновенно мёртв. Классический источник «на тестах работало, а сегодня всё упало». - Переход партнёра в рабочий режим.
PUT /api/partner/mode {"mode":"production"}удаляет все тестовые организации со счетами/подписками и деактивирует их API-ключи — чистый старт by design. Сохраните боевые ключи заново после перехода. Подробнее о режимах — «Песочница и рабочий режим». - Sandbox-ключи не переносятся. Тестовая организация архитектурно не может стать боевой, поэтому её ключи не «мигрируют» — для боевой организации создаётся новый ключ.
- Флаг org-default перескочил. Если у организации не было org-default ключа, первый ключ с
webhook_urlстановится им автоматически; назначение org-default другому ключу снимает флаг с прежнего. На доставку вебхуков это влияет (org-default — второй получатель) — если вебхуки «переехали», проверьте, какой ключ сейчас default.
Правила хранения (коротко и жёстко)
- Оба значения — только на сервере: переменные окружения или менеджер секретов. Никогда в клиентском JS, репозитории, скриншотах и чатах с поддержкой.
- Утечка ключа = кто угодно выставляет счета от вашего имени → немедленно
regenerate. - Утечка секрета = кто угодно подделывает вебхуки «оплачено» → немедленно
regenerate-secret. - Разные среды — разные ключи: тестовая организация со своим ключом, боевая со своим.
Частые ошибки
- Искать «Сгенерировать подпись» до ввода
webhook_url. Кнопка появляется только после сохранения URL. - Класть вебхук-секрет в
X-API-Key—401на любой запрос. - Проверять подпись вебхука API-ключом — «подпись не сходится» навсегда.
- Не сохранить значение при создании. Второго показа не будет — только перегенерация.
- Использовать ключ из песочницы в бою (или наоборот) —
401: ключи привязаны к организации. - Перегенерировать партнёрским эндпоинтом «для проверки» — старый ключ умирает молча.
- Отдавать ключ ИИ-агенту в публичном чате. Агенту достаточно сказать, что ключ лежит в переменной окружения
APIPAY_API_KEY.
Вопросы и ответы
Это одно и то же? Можно использовать API-ключ как секрет?
Нет. Ключ авторизует ваши запросы к ApiPay; секрет проверяет подпись входящих вебхуков. Значения разные, взаимозаменяемости нет.
Где посмотреть ключ ещё раз?
Никак — показывается один раз при создании, дальше только key_hint (хвост). Потеряли — перегенерируйте и обновите интеграции.
Обязателен ли вебхук-секрет?
Формально вебхуки доставляются и без него (заголовка подписи тогда просто нет), но тогда любой может прислать вам фейковый «paid». Для боевой интеграции секрет обязателен по здравому смыслу.
Можно ли иметь несколько API-ключей?
Да, в одной организации — несколько ключей (например, по ключу на систему), у каждого свой webhook_url и секрет. Учтите правило org-default: он — второй получатель вебхуков организации.
Почему после перехода в рабочий режим ключи «пропали»?
Тестовые организации удаляются при переходе партнёра в production вместе со своими ключами — by design. Создайте ключ заново в боевой организации.
Чем отличается партнёрский ключ?
X-Partner-Key — отдельный server-to-server ключ партнёрского API (его секрет имеет формат whsec_…); к мерчантским X-API-Key он отношения не имеет. Если вы обычный мерчант — вам нужен только X-API-Key.