Sign in
Вступ/Автентифікація

Автентифікація та підписання запитів

Підписуйте API-запити за допомогою HMAC-SHA256, використовуючи project UUID та API key.

Кожен API-запит (окрім вхідних webhooks) повинен містити ваш project UUID та підпис запиту. Підпис підтверджує, що запит надійшов саме від вас і ніхто його не змінив під час передачі.

API-ключі

2328.io використовує два ключі, які мають однаковий алгоритм підпису, але охоплюють різні endpoints:

КлючВикористовується для
API keyПлатежі, статичні гаманці, баланс, курси обміну, а також перевірка webhooks для платежів та статичних гаманців
Payout API keyУсі endpoints /v1/payout/* та перевірка webhooks для виплат

Обидва ключі знаходяться у налаштуваннях вашого проєкту на 2328.io. У наведених нижче прикладах "API key" — узагальнена назва; підставте відповідний ключ для endpoint, який викликаєте.

Ніколи не змішуйте два ключі: підписання запиту виплати звичайним API key (або платіжного запиту ключем виплат) повертає помилку підпису.

Обов'язкові заголовки

ЗаголовокТипОбов'язковийОпис
Content-TypestringтакЗавжди application/json
projectstringтакВаш project UUID
signstringтакПідпис запиту HMAC-SHA256, обчислений за допомогою вашого API key
User-AgentstringтакІдентифікує ваш застосунок (наприклад, MyShop/1.4 (+https://myshop.example)). Запити без User-Agent можуть бути заблоковані.

Як працює підпис

Уявіть собі підпис як відбиток тіла запиту. Він формується так:

  1. Серіалізуйте тіло у JSON (компактний — без зайвих пробілів).
  2. Закодуйте цей JSON у base64. Цей крок нормалізує вхідні дані між мовами — щойно це стане звичайним ASCII, кожна мова формуватиме однакові байти для HMAC.
  3. Обчисліть HMAC-SHA256 від base64-рядка, використовуючи ваш API key, потім перетворіть результат на нижній регістр у hex-форматі.

Для GET та інших запитів без тіла підписуйте порожній рядок замість JSON.

Підпис порожнього рядка є константою для конкретного API key. Ви можете кешувати його, якщо робите багато GET-викликів.

Реалізації

PHP
<?php
function apiSign(array $data, string $apiKey): string {
    $json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    $base64 = base64_encode($json);
    return hash_hmac('sha256', $base64, $apiKey);
}

Запити без тіла (GET)

Для запитів із порожнім тілом (наприклад, GET /v1/payout/status/{uuid}) підписуйте порожній рядок:

Shell
SIGN=$(printf '' | openssl dgst -sha256 -hmac "$API_KEY" -hex | awk '{print $NF}')

Повний приклад запиту

Shell
curl -X POST https://api.2328.io/api/v1/payment \
  -H "Content-Type: application/json" \
  -H "User-Agent: MyShop/1.0 (+https://myshop.example)" \
  -H "project: YOUR_PROJECT_UUID" \
  -H "sign: YOUR_HMAC_SIGNATURE" \
  -d '{"amount":"100.00","currency":"USD","order_id":"ORDER-123"}'

Ніколи не розкривайте свій API key у клієнтському коді. Підписуйте запити на бекенді. Витік API key надає будь-кому повний доступ до вашого мерчант-акаунту.

Перевірка підписів webhooks

Коли 2328.io надсилає вам webhook, той самий алгоритм виконується у зворотному напрямку:

  1. Витягніть поле sign із payload.
  2. Закодуйте інші поля у JSON (компактний, без пробілів).
  3. Закодуйте отриманий рядок у base64.
  4. Обчисліть HMAC-SHA256 за допомогою відповідного ключа.
  5. Порівняйте його з отриманим sign, використовуючи порівняння за константний час (hash_equals, crypto.timingSafeEqual, hmac.compare_digest, subtle.ConstantTimeCompare, OpenSSL.fixed_length_secure_compare).

Ключ підпису залежить від джерела webhook:

WebhookКлюч для перевірки
Webhooks платежів та статичних гаманців (/v1/payment, /v1/static-wallet)API key
Webhooks виплат (/v1/payout)Payout API key

Типові помилки перевірки. Ваш JSON-енкодер має видавати точно ті самі байти, що й відправник — інакше Base64 буде відрізнятися і підпис не співпаде.

  • Go: використовуйте json.NewEncoder із SetEscapeHTML(false). Стандартний json.Marshal екранує <, >, & як < і ламає підпис.
  • Python: передавайте ensure_ascii=False у json.dumps. Без цього не-ASCII символи (кирилиця, китайська тощо) екрануються в \uXXXX.
  • Компактний JSON: без пробілів між полями (separators=(",", ":") у Python).
  • Порядок полів (Go): звичайний map[string]any рандомізує ключі при перекодуванні. Використовуйте json.RawMessage, упорядковану структуру або видаляйте sign зі сирих байтів.

Якщо перевірка все одно не проходить, запустіть apiSign на payload самостійно — він має видавати той самий hex-рядок, що й отриманий sign.

Валідний підпис не захищає від повторів. Він лише доводить, що webhook прийшов від 2328.io — і не заважає зловмиснику пізніше повторно надіслати перехоплений webhook. Завжди перевіряйте ідемпотентність за uuid (або txid для статичних гаманців) перед зарахуванням коштів. Відхиляйте з HTTP 401, якщо підпис відсутній або неправильний.

Повні приклади коду на сторінці Webhook-сповіщення. Обробка повторних спроб і правила ідемпотентності — у розділі Найкращі практики.