Introduction
Webhooks can be used to get events from Alviere. For example, when a transaction is settled, Alviere can send an event to your webhook consumer with information about the transaction.
Events are grouped into Subscriptions and each Subscription event will be posted into a URL provided by you at the moment of the subscription.
Note: Alviere sends all events asynchronously so that it doesn't block or slow down any system operation or transaction. All events are actions that already took place.
Subscriptions
Alviere provides several different subscriptions to receive different event types:
-
ACCOUNTprovides information about the lifecycle of your program accounts. -
WALLET_TRANSACTIONprovides information about the lifecycle of wallet transactions. -
ISSUED_CARDprovides information about the lifecycle of all cards issued by Alviere. -
BENEFICIARYprovides information about the lifecycle of all beneficiaries in your program. -
BANK_PMprovides information about the lifecycle of all bank accounts used as payment methods. -
CARD_PMprovides information about the lifecycle of all cards used as payment methods. -
CHECKprovides information about the lifecycle of check deposit transaction. -
DOSSIERprovides information about the lifecycle of all uploaded dossiers. -
PAYMENT_INSTRUMENTprovides information about the lifecycle of all payment instruments.
Payload format
{
"event_uuid": "082fd7f7-7e9e-4679-bd16-ed9f5a55d827",
"program_uuid": "04d3ac6e-82d3-4f52-b82f-6cc0320928af",
"event_date": "2021-06-17T11:02:08.143Z",
"event_retry": 0,
"event_type": [SUBSCRIPTION_TYPE],
"event_version": "2021-11-18.1",
"entity":{
...
}
}
Authentication
Each subscription requires the following information:
-
Subscription type
-
Target endpoint (needs to be a complete HTTPS URL)
-
Authentication method and credentials
-
Version required for each subscription
Authentication Methods
Option 1: Header-Based Authentication (Default)
When we call your endpoint, we include a header called Alviere-Auth with the security key you provided to us.
Option 2: HMAC Signature Authentication
For enhanced security, you can use HMAC-SHA256 signature verification. Provide your shared secret to your implementation manager, and we'll sign each webhook payload. You can then verify the signature to ensure authenticity.
When using HMAC authentication, webhooks include:
-
Alviere-Signature- HMAC-SHA256 signature of the payload -
Alviere-Webhook-Id- Unique identifier for the webhook -
Alviere-Webhook-Timestamp- Unix timestamp when sent
To verify the signature:
-
Construct the payload:
<id>.<timestamp>.<minified-json-body> -
Calculate HMAC-SHA256 using your shared secret
-
Compare with the
Alviere-Signatureheader value
HMAC Verification example:
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
)
func calculateHmac(requestBody []byte, alviereWebhookId, alviereWebhookTimestamp, sharedSecret string) (string, error) {
// remove insignificant spaces (minify)
bodyBuffer := new(bytes.Buffer)
if err := json.Compact(bodyBuffer, requestBody); err != nil { return "", err }
hmacInputBuffer := new(bytes.Buffer)
hmacInputBuffer.WriteString(alviereWebhookId + "." + alviereWebhookTimestamp + ".")
hmacInputBuffer.Write(bodyBuffer.Bytes())
hmacHash := hmac.New(sha256.New, []byte(sharedSecret))
hmacHash.Write(hmacInputBuffer.Bytes())
hmacSum := hmacHash.Sum(nil)
return hex.EncodeToString(hmacSum), nil
}
import hashlib
import hmac
import json
def calculate_hmac(request_body, alviere_webhook_id, alviere_webhook_timestamp, shared_secret):
# remove insignificant spaces (minify)
json_object = json.loads(request_body)
_body = json.dumps(json_object, separators=(',', ':'))
hmac_input = alviere_webhook_id + "." + alviere_webhook_timestamp + "." + _body
hmac_object = hmac.new(shared_secret.encode(), hmac_input.encode(), hashlib.sha256)
return hmac_object.hexdigest()
import { createHmac } from 'node:crypto';
const requestBody = {key: 'value'};
const secret = 'hmac-secret';
const webhookId = 'alviere_webhook_id';
const timestamp = 'alviere_webhook_timestamp';
// remove insignificant spaces (minify)
const body = JSON.stringify(requestBody);
const getHmac = (secret, webhookId, timestamp, body) => {
const hmac = createHmac('sha256', secret);
hmac.update([webhookId, timestamp, body].join('.'));
return hmac.digest('hex');
};
console.log(getHmac(secret, webhookId, timestamp, body));
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.HexFormat;
public class CalculateHmac {
public static String hmacHex(String request_body, String alviere_webhook_id, String alviere_webhook_timestamp, String shared_secret) {
String algorithm = "HmacSHA256";
// remove insignificant spaces (minify)
request_body = minifyJson(request_body);
try {
SecretKeySpec secret_key = new SecretKeySpec(shared_secret.getBytes("UTF-8"), algorithm);
Mac sha256_HMAC = Mac.getInstance(algorithm);
sha256_HMAC.init(secret_key);
String hmac_input = String.join(".", alviere_webhook_id, alviere_webhook_timestamp, request_body);
return HexFormat.of().formatHex(sha256_HMAC.doFinal(hmac_input.getBytes("UTF-8")));
} catch (Exception e) {
throw new RuntimeException("Failed to compute HMAC: " + e.getMessage(), e);
}
}
public static String minifyJson(String jsonString) {
StringBuilder result = new StringBuilder();
boolean inQuotes = false;
for (int i = 0; i < jsonString.length(); i++) {
char c = jsonString.charAt(i);
if (c == '\"') {
result.append(c);
inQuotes = !inQuotes;
} else if (!inQuotes && Character.isWhitespace(c)) {
// skip
} else {
result.append(c);
}
}
return result.toString();
}
}
Processing
Each time we send a message for the provided URL, we expect a 200 HTTP status code, otherwise we will retry the event applying a polynomial backoff starting at 20ms and going up to 2 minutes after each retry.
NOTE that we will continuously retry sending the message and this will impact any other messages in the queue as we strictly maintain messages in order (FIFO).
How to subscribe
Please contact your implementation manager for more information.