Начало работы

Аутентификация

Каждый запрос к API подписывается секретным ключом сервиса. Ключ одновременно определяет сервис, к которому относятся данные, и режим — тестовый или боевой.

API-ключи

Ключи создаются в кабинете: Сервисы → сервис → вкладка API-ключи. Полный ключ показывается один раз, при создании, — в кабинете потом видны только его начало и последние символы.

ПрефиксРежимЧто происходит
sk_test_ТестовыйПлатежи не уходят в Kaspi, оплату можно симулировать. См. Тестовый режим.
sk_live_БоевойРеальные платежи через кассира Kaspi, привязанного к сервису. Создавать боевые ключи могут только администраторы.

Формат ключа: префикс и 32 символа из латинских букв и цифр — sk_(live|test)_[0-9A-Za-z]{32}. Тестовые и боевые данные полностью разделены: тестовый ключ не видит боевые платежи и наоборот. Ключи одного сервиса не дают доступа к платежам другого — для чужого платежа API вернёт 404.

Передача ключа

Передавайте ключ в заголовке Authorization по схеме Bearer. Если ваш HTTP-клиент или прокси использует Authorization для чего-то своего, подойдёт заголовок X-API-Key. Все запросы — только по HTTPS.

curl https://pay.sezgir.com/api/v1/me \
  -H "Authorization: Bearer $SEZGIR_API_KEY"
Если переданы оба заголовка, используется Authorization: Bearer.

Проверка ключа

Запрос GET /me ничего не меняет и подходит для проверки конфигурации при запуске сервиса: он возвращает режим ключа, сервис, к которому ключ относится, и кассира Kaspi, назначенного сервису.

Ответ · 200 OK
{
  "object": "api_key",
  "livemode": true,
  "project": {
    "id": "prj_7HcTq2LwZ9mRk4VbN1sXe8Dy",
    "name": "Интернет-магазин",
    "icon": "🛍️"
  },
  "kaspi_cashier": {
    "name": "Основная касса",
    "organization": "ТОО «Пример»",
    "status": "active"
  }
}

Перед боевым запуском убедитесь, что kaspi_cashier не null и его status равен active: иначе создание боевых платежей вернёт 503 provider_unavailable. Другие значения статуса — needs_reauth (сессия кассира истекла, его нужно переподключить в разделе «Kaspi») и disconnected.

Ошибки аутентификации

HTTPtypeКогда
401authentication_errorКлюч не передан
401authentication_errorСтрока не похожа на ключ (неверный формат — например, лишние пробелы или обрезанный ключ)
401authentication_errorКлюч не найден или отозван
403permission_errorСервис, которому принадлежит ключ, перенесён в архив
Ответ · 401 Unauthorized
{
  "error": {
    "type": "authentication_error",
    "message": "API-ключ недействителен или отозван"
  }
}

Хранение и ротация

  • Храните ключ в переменных окружения или менеджере секретов, а не в репозитории.
  • Используйте ключ только на сервере. Сайт, мобильное приложение и бот обращаются к вашему backend, а тот — к Sezgir Pay.
  • Заведите отдельный ключ на каждое окружение и приложение — так проще отозвать один, не трогая остальные.
  • Ключи, созданные сотрудником, отзываются автоматически, когда его отключают в разделе Команда. Для продакшена создавайте ключи от имени администратора, который не уйдёт вместе с подрядчиком.

Как заменить ключ без простоя

Создайте новый ключ, разверните его во всех местах, где используется старый, убедитесь по времени последнего использования в кабинете, что старый ключ больше не используется, и отзовите его. Отзыв действует сразу: следующий запрос со старым ключом получит 401.

Ключ утёк?
Отзовите его в кабинете немедленно, затем выпустите новый. Проверьте журнал действий и список платежей на предмет неожиданных отмен и возвратов.

Лимиты запросов

На каждый ключ действует лимит 300 запросов в минуту. При превышении API отвечает 429 с типом ошибки rate_limited. Ответы содержат заголовки x-ratelimit-limit, x-ratelimit-remaining и x-ratelimit-reset, а ответ 429 — ещё и retry-after с числом секунд до сброса окна.

Ответ · 429 Too Many Requests
{
  "error": {
    "type": "rate_limited",
    "message": "Слишком много запросов, попробуйте позже"
  }
}

Лимит рассчитан с запасом на обычную работу. Если вы в него упираетесь, скорее всего, вы опрашиваете статус платежей в цикле — подпишитесь на вебхуки и используйте GET /events для сверки.