<!-- Source: https://docs.infraio.xyz/ru/api-reference/authentication -->
<!-- Last updated: 2026-10-04 -->

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

В 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-подписи.
  Только серверный. Относитесь к нему как к паролю базы данных.

> **Important:**
>
> Если secret-ключ когда-либо попал в браузерный бандл, git-репозиторий,
> лог-строку или общий чат — **немедленно отзовите его** из панели.
> Отзыв мгновенный, окна перекрытия нет. Выпустите новый ключ и
> переразверните.

## Подписание запроса

Каждый вызов `/b2b/v1/*` несёт три заголовка:

```http
X-Client-ID:  pk_live_70d0becbd7a53047b0dfe88a960d10ad
X-Timestamp:  1715990400
X-Signature:  9a8b7c6d…             (hex HMAC-SHA256)
```

Подпись вычисляется по канонической строке:

```
METHOD + "\n" + PATH + "\n" + TIMESTAMP + "\n" + BODY
```

- `METHOD` — 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**

```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 };
}
```

**Go**

```go
package infraio

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "strconv"
    "time"
)

func Sign(method, path, body, secret string) (timestamp, signature string) {
    timestamp = strconv.FormatInt(time.Now().Unix(), 10)
    input := method + "\n" + path + "\n" + timestamp + "\n" + body
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write([]byte(input))
    return timestamp, hex.EncodeToString(mac.Sum(nil))
}
```

**Python**

```python
import hmac, hashlib, time

def sign(method: str, path: str, body: str, secret: str):
    timestamp = str(int(time.time()))
    input_ = f"{method}\n{path}\n{timestamp}\n{body}"
    signature = hmac.new(
        secret.encode(), input_.encode(), hashlib.sha256
    ).hexdigest()
    return timestamp, signature
```

## Почему HMAC, а не Bearer?

API на чистых Bearer-токенах отправляет ваш единственный секрет по
сети при каждом запросе. Любой, кто получит лог одного прокси с
TLS-терминацией, получает ключи от вашего аккаунта. Подпись HMAC
означает, что секрет никогда не путешествует — только его производная
подпись, одноразовая (привязанная к этому конкретному запросу и к этой
конкретной минуте).

Компромисс: подпись нужно вычислять для каждого вызова. Серверного SDK
пока нет, но хелпер выше занимает около 15 строк на каждом языке.

## Допуск по времени

Допуск составляет **±5 минут** (300 секунд). Запрос за пределами этого
окна отклоняется с ошибкой `401 invalid_signature`. Из этого следуют
две вещи:

1. **Синхронизируйте часы сервера** через NTP. Долгоживущий cron со
   смещёнными часами будет давать сбои время от времени.
2. **Не предвычисляйте и не ставьте подписи в очередь.** Если запрос
   просидит в очереди повторов более 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'ы,
которые нужны интеграции.

> **Warning:**
>
> **Scope'ы пока не применяются.** Scope'ы записываются на ключе и
> показываются в панели, но любой валидный ключ `sk_…` может вызвать любой
> endpoint `/b2b/v1/*` вашего мерчанта. Не полагайтесь на scope'ы как на
> границу безопасности. Для ограничения доступа используйте ротацию или
> отзыв ключей.

## Неудачная проверка

Если подпись, `X-Client-ID` или временная метка недействительны, запрос
отклоняется с **401 `INVALID_SIGNATURE`** до того, как попадёт в API. Таким
образом подписываются только запросы `/b2b/v1/*`. Webhooks используют
отдельную схему (см. ниже).

## Что дальше

- [Ошибки](https://docs.infraio.xyz/ru/api-reference/errors) — форма ответа при 4xx/5xx.
- [Безопасность → API-ключи](https://docs.infraio.xyz/ru/security/api-keys) — ротация, отзыв,
  что делать, если секрет утёк.
- [Webhooks → Проверка подписи](https://docs.infraio.xyz/ru/webhooks/signature-verification)
  — использует *другую* схему HMAC (заголовок `X-Signature: sha256=…`,
  подписывает `X-Timestamp + "." + raw_body` плюс опциональный
  `X-Signature-Prev` в течение 24-часового grace-окна ротации).
  Не путайте схемы — алгоритм хэширования общий, но подписываемые
  байты и семейство секретов (`whsec_…` против `sk_…`) разные.
