Verify Signatures
Verify webhook authenticity and protect your endpoint.
Critical: Never process webhook payloads without verifying their authenticity when webhook signature verification is enabled.
Best practices
| Practice | Detail |
|---|---|
| HTTPS only | Never accept webhooks over plain HTTP |
| Verify signatures | Validate the X-DigetPay-Signature HMAC signature before processing the payload |
| Allowlist IPs | Restrict inbound webhook traffic to DigetPay outbound IP ranges when available |
| Idempotent handlers | Deduplicate events using transactionId + type |
| Fast 200 response | Acknowledge valid events within seconds and process longer business logic asynchronously |
Important: Reject webhooks with invalid signatures using
401 Unauthorized— do not process the payload.
Signature verification flow
sequenceDiagram
autonumber
participant DigetPay as DigetPay
participant Merchant as Your Server
DigetPay->>Merchant: POST webhook + X-DigetPay-Signature
Merchant->>Merchant: Verify webhook signature
alt Signature valid
Merchant->>Merchant: Accept and process event
Merchant-->>DigetPay: 200 OK
else Signature invalid
Merchant-->>DigetPay: 401 Unauthorized
end
Incoming request format
{
"headers": {
"Content-Type": "application/json",
"X-DigetPay-Signature": "signature-value"
},
"body": {
"transactionId": "2232e99b-0257-47d5-bbfd-022c8951767f",
"orderId": "PAY-1781872369616",
"status": "Approved",
"type": "Sale"
}
}The webhook signature must be verified using the exact signing mechanism provided by DigetPay. Do not modify, parse, or re-serialize the request body before verification if the signing mechanism requires the raw request body.
Signature verification
DigetPay webhook requests include the X-DigetPay-Signature header.
Merchants should verify this signature before processing any webhook event.
The exact signing algorithm, signed payload format, and secret-management flow must match the DigetPay webhook implementation.
Security note: Do not assume an algorithm, canonical payload, timestamp format, or secret format unless it has been confirmed by the DigetPay technical team.
Code examples
The following examples are illustrative only. They demonstrate the general structure of webhook signature verification and must be updated to match the confirmed DigetPay signing specification before being used in production.
<?php
$rawBody = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_DIGETPAY_SIGNATURE'] ?? '';
$webhookSecret = getenv('DIGETPAY_WEBHOOK_SECRET');
if (!$webhookSecret || !$signature) {
http_response_code(401);
exit('Unauthorized');
}
/*
* Replace this verification logic with the exact
* DigetPay signing specification once confirmed.
*/
$expectedSignature = hash_hmac(
'sha256',
$rawBody,
$webhookSecret
);
if (!hash_equals($expectedSignature, $signature)) {
http_response_code(401);
exit('Unauthorized');
}
// Signature is valid.
// Process the webhook event.
http_response_code(200);
echo 'OK';const crypto = require("crypto");
function verifySignature(rawBody, signature, webhookSecret) {
if (!signature || !webhookSecret) {
return false;
}
/*
* Replace this verification logic with the exact
* DigetPay signing specification once confirmed.
*/
const expectedSignature = crypto
.createHmac("sha256", webhookSecret)
.update(rawBody, "utf8")
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expectedSignature),
Buffer.from(signature)
);
}
// The webhook route must have access to the raw request body.
app.post(
"/webhooks/digetpay",
express.raw({ type: "application/json" }),
(req, res) => {
const rawBody = req.body.toString("utf8");
const signature = req.header("X-DigetPay-Signature");
const webhookSecret = process.env.DIGETPAY_WEBHOOK_SECRET;
if (!verifySignature(rawBody, signature, webhookSecret)) {
return res.status(401).send("Unauthorized");
}
const payload = JSON.parse(rawBody);
// Process the verified event asynchronously.
return res.status(200).send("OK");
}
);import os
import hmac
import hashlib
from flask import Flask, request
app = Flask(__name__)
@app.post("/webhooks/digetpay")
def digetpay_webhook():
raw_body = request.get_data()
signature = request.headers.get("X-DigetPay-Signature", "")
webhook_secret = os.environ.get("DIGETPAY_WEBHOOK_SECRET")
if not webhook_secret or not signature:
return "Unauthorized", 401
/*
* Replace this verification logic with the exact
* DigetPay signing specification once confirmed.
*/
expected_signature = hmac.new(
webhook_secret.encode("utf-8"),
raw_body,
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected_signature, signature):
return "Unauthorized", 401
payload = request.get_json()
# Process the verified event asynchronously.
return "OK", 200import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
public class DigetPayWebhookVerifier {
public static boolean verifySignature(
byte[] rawBody,
String receivedSignature,
String webhookSecret) throws Exception {
if (receivedSignature == null || webhookSecret == null) {
return false;
}
/*
* Replace this verification logic with the exact
* DigetPay signing specification once confirmed.
*/
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(
webhookSecret.getBytes(StandardCharsets.UTF_8),
"HmacSHA256"
);
mac.init(secretKey);
byte[] digest = mac.doFinal(rawBody);
StringBuilder hex = new StringBuilder();
for (byte b : digest) {
hex.append(String.format("%02x", b));
}
return MessageDigest.isEqual(
hex.toString().getBytes(StandardCharsets.UTF_8),
receivedSignature.getBytes(StandardCharsets.UTF_8)
);
}
}The code examples above are reference implementations only. Confirm the exact DigetPay webhook signing contract with the DigetPay technical team before using them in production.
Replay protection
A secure webhook implementation should also consider replay attacks, where a previously valid webhook request is submitted again.
The current documentation does not confirm whether DigetPay includes a timestamp, nonce, or other replay-protection value in the webhook signature.
Therefore, do not implement timestamp validation or claim timestamp-based replay protection unless the DigetPay signing specification explicitly provides it.
Regardless of the signature mechanism, webhook handlers should be idempotent.
Use an appropriate event identifier, such as:
transactionId + typeto prevent the same webhook event from triggering duplicate business actions.
If DigetPay supports timestamp-based signing, this section should be updated with the exact timestamp header, signing format, and allowed clock-skew window.
Webhook secret
The webhook signing secret must be stored securely and must never be exposed in frontend code, source control, or production logs.
Use a secrets manager or equivalent secure configuration mechanism.
{
"webhookSecret": "store-in-secrets-manager",
"storage": "Never commit to Git or log in production"
}Do not use the examples above to assume a specific webhook-secret generation or rotation process until the DigetPay implementation is confirmed.
IP allowlisting
IP allowlisting can be used as an additional network-level security control.
Merchant infrastructure can restrict inbound webhook traffic to DigetPay's published outbound webhook IP ranges.
IP allowlisting does not replace signature verification. When signature verification is enabled, always validate the webhook signature before processing the event.
Production documentation: DigetPay's authoritative outbound webhook IP ranges should be published here once confirmed by the DigetPay infrastructure team.
Response handling
For a valid webhook that has passed authentication and has been accepted for processing, return:
HTTP/1.1 200 OKFor a missing or invalid signature, return:
HTTP/1.1 401 UnauthorizedDo not process an unauthenticated webhook payload.
Keep webhook endpoints fast and move longer business operations to asynchronous processing where possible.
Security checklist
Before going live, confirm that:
- The webhook endpoint uses HTTPS.
- The
X-DigetPay-Signatureheader is validated. - The exact DigetPay signing algorithm and payload format are implemented.
- Signature comparison uses a timing-safe comparison method where supported.
- The webhook secret is stored securely.
- The webhook secret is never logged or committed to source control.
- Duplicate events are handled idempotently.
- Invalid signatures return
401 Unauthorized. - Valid events return
200 OK. - DigetPay outbound webhook IP ranges are allowlisted where required.
- IP allowlisting is treated as an additional security control, not a replacement for signature verification.
- Replay-protection requirements have been confirmed with the DigetPay technical team.
Related guides
Updated 17 days ago

