Sign in
Wprowadzenie/Uwierzytelnianie

Uwierzytelnianie i podpisywanie żądań

Podpisuj żądania API za pomocą HMAC-SHA256, używając project UUID i klucza API.

Każde żądanie API (z wyjątkiem przychodzących webhooków) musi zawierać Twój project UUID oraz podpis żądania. Podpis potwierdza, że żądanie pochodzi od Ciebie i nie zostało zmodyfikowane podczas przesyłania.

Klucze API

2328.io korzysta z dwóch kluczy, które używają tego samego algorytmu podpisywania, ale obsługują różne endpointy:

KluczStosowany do
API keyPłatności, statyczne portfele, saldo, kursy walutowe oraz weryfikacja webhooków płatności / statycznych portfeli
Payout API keyWszystkie endpointy /v1/payout/* oraz weryfikacja webhooków wypłat

Oba klucze znajdują się w ustawieniach Twojego projektu na 2328.io. Poniższe przykłady używają nazwy „API key" w sposób ogólny — podstaw odpowiedni klucz dla wywoływanego endpointu.

Nigdy nie mieszaj obu kluczy: podpisanie żądania wypłaty zwykłym kluczem API (lub żądania płatności kluczem wypłaty) zwróci błąd podpisu.

Wymagane nagłówki

NagłówekTypWymaganyOpis
Content-TypestringtakZawsze application/json
projectstringtakTwój project UUID
signstringtakPodpis HMAC-SHA256 żądania, obliczony za pomocą Twojego klucza API
User-AgentstringtakIdentyfikuje Twoją aplikację (np. MyShop/1.4 (+https://myshop.example)). Żądania bez User-Agent mogą zostać zablokowane.

Jak działa podpis

Podpis można rozumieć jako odcisk palca treści żądania. Tworzony jest poprzez:

  1. Serializację treści do formatu JSON (kompaktowo — bez dodatkowych białych znaków).
  2. Zakodowanie tego JSON-a w base64. Ten krok normalizuje wejście pomiędzy językami — gdy mamy zwykły ASCII, każdy język produkuje te same bajty dla HMAC.
  3. Obliczenie HMAC-SHA256 ciągu base64 przy użyciu Twojego klucza API, a następnie konwersję wyniku na hex zapisany małymi literami.

Dla żądań GET oraz innych typów żądań bez treści podpisuj pusty ciąg zamiast JSON-a.

Podpis pustego ciągu jest stały dla danego klucza API. Możesz go zbuforować, jeśli wykonujesz wiele wywołań GET.

Implementacje

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

Żądania bez treści (GET)

Dla żądań z pustą treścią (np. GET /v1/payout/status/{uuid}) podpisuj pusty ciąg:

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

Pełny przykład żądania

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"}'

Nigdy nie ujawniaj swojego klucza API w kodzie po stronie klienta. Podpisuj żądania na swoim backendzie. Wyciek klucza API daje każdemu pełny dostęp do Twojego konta sprzedawcy.

Weryfikacja podpisów webhooków

Gdy 2328.io wysyła webhook, ten sam algorytm jest wykonywany w odwrotnej kolejności:

  1. Wyciągnij pole sign z payloadu.
  2. Zakoduj pozostałe pola jako JSON (kompaktowo, bez białych znaków).
  3. Zakoduj ten ciąg w base64.
  4. Oblicz HMAC-SHA256 z odpowiednim kluczem.
  5. Porównaj wynik z otrzymanym sign przy użyciu porównania w czasie stałym (hash_equals, crypto.timingSafeEqual, hmac.compare_digest, subtle.ConstantTimeCompare, OpenSSL.fixed_length_secure_compare).

Klucz podpisujący zależy od źródła webhooka:

WebhookKlucz do weryfikacji
Webhooki płatności / statycznych portfeli (/v1/payment, /v1/static-wallet)API key
Webhooki wypłat (/v1/payout)Payout API key

Typowe pułapki weryfikacji. Twój enkoder JSON musi produkować dokładnie te same bajty, które wyprodukował nadawca — inaczej Base64 będzie różny i podpis się nie zgodzi.

  • Go: użyj json.NewEncoder z SetEscapeHTML(false). Domyślny json.Marshal escapeuje <, >, & na < i psuje podpis.
  • Python: przekaż ensure_ascii=False do json.dumps. Bez tego znaki spoza ASCII (cyrylica, chiński, …) są escapeowane do \uXXXX.
  • Kompaktowy JSON: bez białych znaków między polami (separators=(",", ":") w Pythonie).
  • Kolejność pól (Go): zwykła map[string]any randomizuje klucze przy ponownym kodowaniu. Użyj json.RawMessage, uporządkowanej struktury lub usuń sign z surowych bajtów.

Jeśli weryfikacja nadal zawodzi, uruchom apiSign na payloadzie samodzielnie — musi wyprodukować ten sam ciąg szesnastkowy co otrzymane sign.

Poprawny podpis nie chroni przed replayami. Dowodzi tylko, że webhook pochodzi z 2328.io — nie zapobiega ponownemu wysłaniu przechwyconego webhooka przez atakującego później. Zawsze sprawdzaj idempotentność po uuid (lub txid dla statycznych portfeli) zanim zaksięgujesz środki. Odrzuć z HTTP 401, jeśli podpis jest brakujący lub błędny.

Pełne przykłady kodu znajdziesz na Webhook Notifications. Obsługa ponawiania prób i reguły idempotentności są w Najlepszych praktykach.