Sign in
Introductie/Authenticatie

Authenticatie en ondertekening van verzoeken

Onderteken API-verzoeken met HMAC-SHA256 met behulp van je project UUID en API key.

Elk API-verzoek (behalve inkomende webhooks) moet je project UUID en een handtekening van het verzoek bevatten. De handtekening bewijst dat het verzoek van jou afkomstig is en dat niemand het onderweg heeft gewijzigd.

API keys

2328.io gebruikt twee keys die hetzelfde ondertekeningsalgoritme delen, maar verschillende endpoints bestrijken:

KeyGebruikt voor
API keyBetalingen, statische wallets, saldo, wisselkoersen en verificatie van betaling- / statische-wallet-webhooks
Payout API keyAlle /v1/payout/*-endpoints en verificatie van uitbetalingswebhooks

Beide keys staan in je projectinstellingen op 2328.io. De voorbeelden hieronder zeggen generiek "API key" — vervang door de juiste key voor het endpoint dat je aanroept.

Meng de twee keys nooit: een uitbetalingsverzoek ondertekenen met de gewone API key (of een betalingsverzoek met de payout key) levert een handtekeningfout op.

Vereiste headers

HeaderTypeVereistBeschrijving
Content-TypestringjaAltijd application/json
projectstringjaJe project UUID
signstringjaHMAC-SHA256-handtekening van het verzoek, berekend met je API key
User-AgentstringjaIdentificeert je applicatie (bijv. MyShop/1.4 (+https://myshop.example)). Verzoeken zonder User-Agent kunnen worden geblokkeerd.

Hoe de handtekening werkt

Zie de handtekening als een vingerafdruk van de body van het verzoek. Hij wordt opgebouwd door:

  1. De body te serialiseren naar JSON (compact — geen extra whitespace).
  2. Die JSON te encoderen in base64. Deze stap normaliseert de input over talen heen — zodra het pure ASCII is, produceert elke taal dezelfde bytes voor HMAC.
  3. HMAC-SHA256 te berekenen over de base64-string met je API key, en het resultaat te converteren naar lowercase hex.

Voor GET en andere verzoeken zonder body onderteken je in plaats van de JSON een lege string.

De handtekening van de lege string is constant voor een gegeven API key. Je kunt hem cachen als je veel GET-aanroepen doet.

Implementaties

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

Verzoeken zonder body (GET)

Voor verzoeken zonder body (bijv. GET /v1/payout/status/{uuid}) onderteken je een lege string:

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

Volledig voorbeeld van een verzoek

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

Stel je API key nooit bloot in client-side code. Onderteken verzoeken op je backend. Een gelekte API key geeft iedereen volledige toegang tot je merchantaccount.

Webhook-handtekeningen verifiëren

Wanneer 2328.io je een webhook stuurt, draait hetzelfde algoritme in omgekeerde richting:

  1. Haal het sign-veld uit de payload.
  2. Encodeer de overige velden als JSON (compact, geen whitespace).
  3. Encodeer die string in base64.
  4. Bereken HMAC-SHA256 met de juiste key.
  5. Vergelijk met de ontvangen sign met behulp van een constant-time vergelijking (hash_equals, crypto.timingSafeEqual, hmac.compare_digest, subtle.ConstantTimeCompare, OpenSSL.fixed_length_secure_compare).

De ondertekeningskey hangt af van de bron van de webhook:

WebhookKey voor verificatie
Betaling- / statische-wallet-webhooks (/v1/payment, /v1/static-wallet)API key
Uitbetalingswebhooks (/v1/payout)Payout API key

Veelvoorkomende verificatie-valkuilen. Je JSON-encoder moet exact dezelfde bytes produceren als de verzender — anders verschilt de Base64 en zal de handtekening niet kloppen.

  • Go: gebruik json.NewEncoder met SetEscapeHTML(false). De standaard json.Marshal escapet <, >, & naar < en breekt de handtekening.
  • Python: geef ensure_ascii=False mee aan json.dumps. Zonder dit worden niet-ASCII-tekens (cyrillisch, Chinees, …) ge-escaped naar \uXXXX.
  • Compacte JSON: geen witruimte tussen velden (separators=(",", ":") in Python).
  • Veldvolgorde (Go): een gewone map[string]any randomiseert sleutels bij her-encoderen. Gebruik json.RawMessage, een geordende struct of strip sign uit de ruwe bytes.

Als verificatie blijft falen, voer dan zelf apiSign uit op de payload — die moet dezelfde hex-string produceren als de ontvangen sign.

Een geldige handtekening voorkomt geen replays. Het bewijst alleen dat de webhook van 2328.io komt — het belet een aanvaller niet om een opgevangen webhook later opnieuw te posten. Controleer altijd idempotentie via uuid (of txid voor statische wallets) voordat je geld bijschrijft. Weiger met HTTP 401 als de handtekening ontbreekt of fout is.

Volledige codevoorbeelden staan op Webhook Notifications. Retry-afhandeling en idempotentieregels staan in Best practices.