Secure your webhook
Orbi Payments Gateway signs every webhook delivery to allow you to verify authenticity, detect tampering, and protect against replay attacks. This page explains how webhook signatures are generated, how to verify them, and the security requirements your integration must follow.
Why verification is required
Webhook endpoints are publicly accessible by design. Without verification, a malicious actor could forge requests and trigger false events in your system.
To prevent this, Orbi:
- Cryptographically signs every webhook payload
- Includes a timestamp to prevent replay attacks
- Provides environment-specific public keys for verification
You must verify every webhook request before processing it.
Webhook security headers
Each webhook delivery includes the following headers:
x-signature— Base64-encoded cryptographic signaturex-timestamp— Unix timestamp in milliseconds indicating when the event was generatedx-idempotency-key— Unique identifier for safe deduplication
Signature algorithm
Orbi uses asymmetric cryptography to sign webhook payloads:
- Algorithm: RSASSA-PKCS1-v1_5 with SHA-256
Signatures are generated using a private key managed securely by Orbi. You verify signatures using Orbi’s public key.
Signed payload format
The string that Orbi signs is constructed as:
{timestamp}.{raw_payload}
Where:
timestampis the value from thex-timestampheader (milliseconds)raw_payloadis the raw request body, exactly as received
Example
1713206400123.{"event":"order:paid","data":{...},"object_type":"object","timestamp":1713206400123}
The resulting signature is Base64-encoded and sent in the x-signature header.
Public keys
Webhook signatures must be verified using the public key corresponding to the environment sending the event.
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyERRtx6cjopbjH2/kJ+j
zqEERTCBwRvKIeELdXqkzokmKUcWgqIMLTBz+8ovdDd0ntqxHyrgE2NXVwSXbkul
+EPi46IPtNTbrwmVsWGTCK8etgdchF1zKUOcHy6Em+pXS8iATn+mkBUav/Bn/kP9
cNrqEyfN7N38+zyFdjVe2S58iM1ZEBo6yaQRDBDS7eejoGGzgQzx4H1MJjCIR60D
fiCTz2jjXsOb8IIAXzyudCVxsBlsRvQi9jqaLeMu7HfzsWDHBUpgQWKvHlHJSWO/
nxT7oCqIPAMy+utS5pAtfszwozTf5n15QjLr+WU/96F3cPSXeVcKJo0a1AI7+7mt
dQIDAQAB
-----END PUBLIC KEY----------BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyBH0pVqnA/v7aaJyX/eD
F3NdLEku2zjPyD1rIqmgwuDQVoMDxzvmL5x3iWPO4ISQzeAHkSWsUh4j7+qGMogF
IPKI7SblPBGv6At81JvqglvPaRp3I/tcO8zYu4fMCYU9BJ6hY7xggNxU2SxVm8gk
RGgWCSZSeaiSnu9djPMUp/XIEbT4D3bLFFqoOUnXnP73UDmcuVLgz4VTPNWDdK4c
pfyxj2v7yffoasg0eMWwyJK64czQdNymrbX5wOs+LRSrT+2g8AVAI6+R794QwBOX
Jma396logR0XO2ICx9jfVDZMxLngED/QYNmh9GktqbkzN94UFfmPr2YxJWoQIWSC
hQIDAQAB
-----END PUBLIC KEY-----Important
Using the wrong public key (for example, sandbox key for production events) will cause verification to fail.
Raw payload requirement
Signature verification requires the raw request body.
Many frameworks automatically parse JSON and re-serialize it, which changes formatting and breaks signature verification.
You must configure your server to access the raw payload bytes before JSON parsing.
Critical
Always verify the signature using the raw payload, not a reconstructed or stringified object.
Verify a webhook signature (Node.js example)
The example below demonstrates how to verify a webhook signature using Node.js.
import crypto from "crypto";
function verifyOrbiWebhookSignature({
timestamp,
rawBody,
signatureBase64,
publicKeyPem,
}: {
timestamp: string;
rawBody: string;
signatureBase64: string;
publicKeyPem: string;
}): boolean {
const dataToVerify = `${timestamp}.${rawBody}`;
const verifier = crypto.createVerify("RSA-SHA256");
verifier.update(dataToVerify);
verifier.end();
return verifier.verify(
publicKeyPem,
Buffer.from(signatureBase64, "base64")
);
}Replay protection
To prevent replay attacks:
- Validate the webhook signature.
- Verify the timestamp is recent (for example, within a 5-minute tolerance).
- Reject requests with timestamps outside the allowed window.
- Use the
x-idempotency-keyto ensure the event is processed only once.
Handling verification failures
If verification fails:
- Do not process the event
- Respond with a non-
2xxstatus code (for example400or401) - Log the failure for investigation
- Ensure sensitive headers are not logged in plaintext
Security best practices
- Always verify the signature before processing the event
- Enforce HTTPS on your webhook endpoint
- Use environment-specific public keys
- Implement timestamp validation and idempotency checks
- Rotate keys only when instructed by Orbi support
Updated 7 months ago