Sign in
Introduzione/Autenticazione

Autenticazione e Firma delle Richieste

Firma le richieste API con HMAC-SHA256 utilizzando il tuo project UUID e l'API key.

Ogni richiesta API (eccetto i webhook in entrata) deve contenere il tuo project UUID e una firma della richiesta. La firma dimostra che la richiesta proviene da te e che nessuno l'ha modificata lungo il percorso.

API key

2328.io utilizza due chiavi che condividono lo stesso algoritmo di firma ma coprono endpoint differenti:

ChiaveUtilizzata per
API keyPagamenti, wallet statici, saldo, tassi di cambio e verifica dei webhook di pagamento / wallet statico
Payout API keyTutti gli endpoint /v1/payout/* e la verifica dei webhook di prelievo

Entrambe le chiavi si trovano nelle impostazioni del progetto su 2328.io. Negli esempi seguenti viene indicato genericamente "API key" — sostituiscila con quella corretta in base all'endpoint che stai chiamando.

Non mescolare mai le due chiavi: firmare una richiesta di prelievo con l'API key normale (o una richiesta di pagamento con la payout key) restituisce un errore di firma.

Header obbligatori

HeaderTipoObbligatorioDescrizione
Content-TypestringSempre application/json
projectstringIl tuo project UUID
signstringFirma HMAC-SHA256 della richiesta, calcolata con la tua API key
User-AgentstringIdentifica la tua applicazione (es. MyShop/1.4 (+https://myshop.example)). Le richieste senza User-Agent possono essere bloccate.

Come funziona la firma

Pensa alla firma come a un'impronta digitale del body della richiesta. Viene costruita così:

  1. Serializzando il body in JSON (compatto — senza spazi extra).
  2. Codificando in Base64 quel JSON. Questo passaggio normalizza l'input tra i linguaggi — una volta che è ASCII puro, ogni linguaggio produce gli stessi byte per HMAC.
  3. Calcolando HMAC-SHA256 della stringa Base64 utilizzando la tua API key, quindi convertendo il risultato in hex minuscolo.

Per le richieste GET e gli altri tipi senza body, firma una stringa vuota invece del JSON.

La firma della stringa vuota è costante per una determinata API key. Puoi memorizzarla in cache se effettui molte chiamate GET.

Implementazioni

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

Richieste senza body (GET)

Per le richieste con body vuoto (es. GET /v1/payout/status/{uuid}), firma una stringa vuota:

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

Esempio completo di richiesta

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

Non esporre mai la tua API key nel codice lato client. Firma le richieste sul tuo backend. Una API key compromessa concede a chiunque pieno accesso al tuo account merchant.

Verifica delle firme dei webhook

Quando 2328.io ti invia un webhook, viene eseguito lo stesso algoritmo in senso inverso:

  1. Estrai il campo sign dal payload.
  2. Codifica in JSON i campi rimanenti (compatto, senza spazi).
  3. Codifica in Base64 quella stringa.
  4. Calcola HMAC-SHA256 con la chiave appropriata.
  5. Confrontala con il sign ricevuto utilizzando un confronto a tempo costante (hash_equals, crypto.timingSafeEqual, hmac.compare_digest, subtle.ConstantTimeCompare, OpenSSL.fixed_length_secure_compare).

La chiave di firma dipende dalla sorgente del webhook:

WebhookChiave per la verifica
Webhook di pagamento / wallet statico (/v1/payment, /v1/static-wallet)API key
Webhook di prelievo (/v1/payout)Payout API key

Errori comuni di verifica. Il tuo encoder JSON deve produrre gli stessi byte identici prodotti dal mittente — altrimenti il Base64 differisce e la firma non corrisponderà.

  • Go: usa json.NewEncoder con SetEscapeHTML(false). Il json.Marshal predefinito esegue l'escape di <, >, & in < e rompe la firma.
  • Python: passa ensure_ascii=False a json.dumps. Senza, i caratteri non ASCII (cirillico, cinese, …) vengono fatti escape come \uXXXX.
  • JSON compatto: nessuno spazio tra i campi (separators=(",", ":") in Python).
  • Ordine dei campi (Go): un semplice map[string]any randomizza le chiavi alla ri-codifica. Usa json.RawMessage, una struct ordinata, oppure rimuovi sign dai byte grezzi.

Se la verifica continua a fallire, esegui tu stesso apiSign sul payload — deve produrre la stessa stringa esadecimale del sign ricevuto.

Una firma valida non previene i replay. Dimostra solo che il webhook proviene da 2328.io — non impedisce a un attaccante di ripubblicare in seguito un webhook catturato. Verifica sempre l'idempotenza tramite uuid (o txid per i wallet statici) prima di accreditare i fondi. Rifiuta con HTTP 401 se la firma è mancante o errata.

Gli esempi di codice completi sono su Webhook Notifications. La gestione dei retry e le regole di idempotenza sono in Best practice.