Аутентификация
В InfraIO Pay есть два API-уровня с разными моделями аутентификации. Выбирайте тот, который соответствует вызывающей стороне:
| Уровень | Префикс пути | Аудитория | Аутентификация |
|---|---|---|---|
| Мерчантский B2B | /b2b/v1/* | Ваш сервер | Подпись запросов HMAC-SHA256 |
| Панель управления | Используется панелью мерчанта | Браузерные сессии для панели мерчанта | Bearer JWT |
Эта страница описывает B2B-уровень — тот, который вы вызываете со своего сервера с парой API-ключей. Уровень панели управления используется панелью мерчанта InfraIO Pay и не является публичным интеграционным уровнем.
Всегда отправляйте полный путь вместе с префиксом /b2b и подписывайте
этот же путь (см. ниже).
Endpoint’ы
| Окружение | Base URL |
|---|---|
| Тестовое | https://api-dev.infraio.xyz |
| Боевое | https://api.infraio.xyz |
Шаблон URL тот же — окружение определяется по префиксу ключа
(pk_test_… или pk_live_…), а не по URL.
Пара ключей
Из панели мерчанта вы получаете два значения (Developers → API keys → + Add key):
- Publishable-ключ (
pk_test_…илиpk_live_…) — идентифицирует ваш аккаунт. Передаётся какX-Client-ID. Безопасно встраивать в ваш браузерный бандл (SDK уже это делает). - Secret-ключ (
sk_test_…илиsk_live_…) — ключ HMAC-подписи. Только серверный. Относитесь к нему как к паролю базы данных.
Если secret-ключ когда-либо попал в браузерный бандл, git-репозиторий, лог-строку или общий чат — немедленно отзовите его из панели. Отзыв мгновенный, окна перекрытия нет. Выпустите новый ключ и переразверните.
Подписание запроса
Каждый вызов /b2b/v1/* несёт три заголовка:
X-Client-ID: pk_live_70d0becbd7a53047b0dfe88a960d10ad
X-Timestamp: 1715990400
X-Signature: 9a8b7c6d… (hex HMAC-SHA256)Подпись вычисляется по канонической строке:
METHOD + "\n" + PATH + "\n" + TIMESTAMP + "\n" + BODYMETHOD— HTTP-глагол в верхнем регистре (POST,GET, …).PATH— путь запроса включая префикс/b2b, без хоста и без query-строки (например,/b2b/v1/checkout-sessions/quick). Префикс должен присутствовать. Query-параметры не подписываются — дляGET …?cursor=…&limit=20подписывайте только путь, без части?….TIMESTAMP— unix-секунды как десятичная строка (например,"1715990400"), точно совпадающая сX-Timestamp.BODY— сырые байты тела запроса. Пустая строка дляGET/DELETE.
Подписывайте с помощью HMAC-SHA256 ключом secret, вывод hex:
Node / TS
import { createHmac } from "node:crypto";
function sign({ method, path, body, secret }: {
method: string; path: string; body: string; secret: string;
}) {
const timestamp = Math.floor(Date.now() / 1000).toString();
const input = [method.toUpperCase(), path, timestamp, body].join("\n");
const signature = createHmac("sha256", secret).update(input).digest("hex");
return { timestamp, signature };
}Почему HMAC, а не Bearer?
API на чистых Bearer-токенах отправляет ваш единственный секрет по сети при каждом запросе. Любой, кто получит лог одного прокси с TLS-терминацией, получает ключи от вашего аккаунта. Подпись HMAC означает, что секрет никогда не путешествует — только его производная подпись, одноразовая (привязанная к этому конкретному запросу и к этой конкретной минуте).
Компромисс: подпись нужно вычислять для каждого вызова. Серверного SDK пока нет, но хелпер выше занимает около 15 строк на каждом языке.
Допуск по времени
Допуск составляет ±5 минут (300 секунд). Запрос за пределами этого
окна отклоняется с ошибкой 401 invalid_signature. Из этого следуют
две вещи:
- Синхронизируйте часы сервера через NTP. Долгоживущий cron со смещёнными часами будет давать сбои время от времени.
- Не предвычисляйте и не ставьте подписи в очередь. Если запрос просидит в очереди повторов более 5 минут, его подпись истечёт.
Scope’ы ключей
Secret-ключи несут один или несколько из этих наборов scope’ов:
| Scope | Назначение |
|---|---|
read | Чтение списков и единичных заказов, сессий, возвратов |
write_order | Создание сессий checkout, заказов |
write_refund | Выпуск возвратов, генерация refund-request token’ов |
webhook_manage | Создание/обновление/удаление webhook-endpoint’ов |
По умолчанию панель выдаёт ключ с «полным доступом» (все четыре scope’а). Вы можете выпустить ключ с ограниченным scope’ом из Developers → API keys → + Add key, отметив только те scope’ы, которые нужны интеграции.
Scope’ы пока не применяются. Scope’ы записываются на ключе и
показываются в панели, но любой валидный ключ sk_… может вызвать любой
endpoint /b2b/v1/* вашего мерчанта. Не полагайтесь на scope’ы как на
границу безопасности. Для ограничения доступа используйте ротацию или
отзыв ключей.
Неудачная проверка
Если подпись, X-Client-ID или временная метка недействительны, запрос
отклоняется с 401 INVALID_SIGNATURE до того, как попадёт в API. Таким
образом подписываются только запросы /b2b/v1/*. Webhooks используют
отдельную схему (см. ниже).
Что дальше
- Ошибки — форма ответа при 4xx/5xx.
- Безопасность → API-ключи — ротация, отзыв, что делать, если секрет утёк.
- Webhooks → Проверка подписи
— использует другую схему HMAC (заголовок
X-Signature: sha256=…, подписываетX-Timestamp + "." + raw_bodyплюс опциональныйX-Signature-Prevв течение 24-часового grace-окна ротации). Не путайте схемы — алгоритм хэширования общий, но подписываемые байты и семейство секретов (whsec_…противsk_…) разные.