Configuration and Delivery Confirmation
The webhook URL is defined per Processor and, for now, this configuration must be requested from the Paag team.
A webhook delivery is considered successful when Paag receives a 2xx status from the configured endpoint. Any response outside the 2xx range is treated as a failure and triggers the retry policy.
Retry Policy
When a delivery fails (response other than 2xx), the system resends the webhook once per minute, for up to 10 minutes, totaling up to 10 attempts if no 2xx response is received. This strategy balances delivery reliability without overloading destination systems.
Signature Verification
Every request includes the x-paag-webhook-signature header, which contains an HMAC signature of the payload, encoded in Base64. The signature uses the SHA-256 algorithm with the secret key shared with your platform.
How the signature is generated
- The HMAC-SHA256 of the webhook's raw body is computed using the shared secret → result in hexadecimal.
- The hexadecimal result is then encoded in Base64.
Important: use exactly the bytes of the received raw body in the calculation. Re-serializing the JSON may alter spaces/order and invalidate the comparison.

This is an example of how you can verify the signature in a Node.js application:
var crypto = require('crypto');
// The webhook body
data = hmac.update('{"event":"transfer","transaction": .... }]}}');
var hmac = crypto.createHmac('sha256', 'SECRET_SHARED_WITH_YOU');
hmacSignature = data.digest('hex');
generatedSignature = Buffer.from(hmacSignature).toString('base64')
var expectedSignature = 'OGJkZGEzNTg0YWNiZmUwYzgzNjgyZjkzY2QzZDM5ZWJiNTdiNDFkNDMxMzc4YmI0ZjE5ZTZmM2IzOTEwYTBiZg=='
console.log("Expected Signature: " + expectedSignature);
console.log("Generated Signature: " + generatedSignature);
console.log(`Equal: ${generatedSignature == expectedSignature}`);This is an example of how you can verify the signature in a Go application:
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"fmt"
)
func main() {
// The webhook body
data := []byte(`{"event":"transfer","transaction":{....}]}}`)
secret := []byte("SECRET_SHARED_WITH_YOU")
// create a new HMAC by defining the hash type and the key
algo := hmac.New(sha256.New, secret)
// compute the HMAC
algo.Write(data)
dataHmac := algo.Sum(nil)
hmacHex := hex.EncodeToString(dataHmac)
//secretHex := hex.EncodeToString(secret)
toBase64 := base64.StdEncoding.EncodeToString([]byte(hmacHex))
expected := "OGJkZGEzNTg0YWNiZmUwYzgzNjgyZjkzY2QzZDM5ZWJiNTdiNDFkNDMxMzc4YmI0ZjE5ZTZmM2IzOTEwYTBiZg=="
fmt.Printf("HMAC_SHA256: %s \n", toBase64)
fmt.Printf("Comparing: %t", toBase64 == expected)
}