Websites11 min read

Secure Payment Webhooks: Signature Verification & Idempotency (2026)

Mohamed Bah·Fondateur, Kolonell
August 24, 2026
Share:
Secure Payment Webhooks: Signature Verification & Idempotency (2026)

Secure Payment Webhooks: Signature Verification & Idempotency (2026)

Websites

The verdict in three sentences

A payment webhook is the call the operator sends to your server to say "this payment succeeded"; if it's not verified, an attacker can forge it and trigger a delivery without ever paying. The defense comes in three layers: HMAC signature verification, an idempotency key against replay, and a status re-check directly against the operator's API. Without these layers, fraud is 100% free; with them, it becomes nearly impossible.

The hole: simulating a successful payment

The scenario is mundane. Your code listens on a webhook URL and, on receiving a "status=success" message, marks the order paid and triggers delivery. If you don't verify the message truly comes from the operator, an attacker sends that message themselves with the right order number and walks off with the goods. HMAC signatures solve this: the operator signs each message with a shared secret, and you recompute the signature to confirm the origin.

Mechanism by operatorSignature headerMethodRisk without verification
WaveHMAC signature in headerHMAC-SHA256Fake payment accepted
Paystackx-paystack-signatureHMAC-SHA512Fake payment accepted
Flutterwaveverif-hashShared secret hashFake payment accepted
StripeStripe-SignatureHMAC-SHA256 + timestampFake payment accepted
Orange MoneyToken / signature per integrationVariableFake payment accepted

The golden rule: never trust the webhook body alone. The signature proves the origin, not the business content.

The three layers of defense

Each layer blocks a different attack. Together, they cover forgery, replay and lying about the amount.

LayerWhat it blocksHow
HMAC signature verificationForged messageRecompute the hash with the secret
Idempotency keyReplay of the same messageStore the event ID, ignore duplicates
Status re-check via APIFake amount / fake statusQuery the API with the transaction ID
IP allowlistUnknown sourceOnly accept operator IPs
Timestamp / windowDelayed replayReject messages that are too old

The status re-check is the ultimate safety net: even if everything else fails, querying the operator's API with the transaction ID confirms the true amount and status before delivery.

Idempotency, why it's vital

Operators sometimes resend the same webhook several times (unstable network, automatic retry). Without idempotency, you risk crediting an order twice, shipping goods twice or double-counting revenue. The solution: store the unique identifier of each received event and ignore any duplicate. It's also protection against deliberate replay by an attacker.

Mini case study

Need a professional website?

Kolonell builds websites that attract clients, optimized for the Sénégalese market. Free quote in 2 minutes.

Kwame launches an airtime and top-up store in Accra. At first, his webhook accepts any "success" message. In one week, an attacker simulates 40 payments and walks off with 600,000 FCFA of credit. Kwame has the three layers added: HMAC verification (Paystack via x-paystack-signature), idempotency on the event ID, and a status re-check via the API before each delivery. Fix cost: about 300,000 FCFA, one time. Fraud drops to zero. The fix paid for itself in half a prevented attack.

FAQ

Is signature verification enough on its own?

No. It proves the message comes from the operator, but a replay of the same message stays possible without idempotency, and an amount bug can slip through. The combination of signature + idempotency + status re-check is the standard.

Where do I find the signature secret?

In the operator's dashboard (Wave, Paystack, Flutterwave, Stripe), under webhooks or API keys. This secret must stay server-side, never in client code or a public repository.

Do I really need to re-check status via the API?

It's best practice for sensitive amounts. Even with a valid signature, querying the API with the transaction ID guarantees the true status and amount before delivery. It's a fast, cheap call.

Is the IP allowlist mandatory?

No, but it's a free layer: only accepting the IP ranges published by the operator reduces the attack surface. Watch for operators who change their IPs without notice.

How much does securing a webhook cost?

A 2026 order of magnitude: 200,000 to 400,000 FCFA to implement the three layers cleanly on an existing integration. That's negligible against the risk of a single successful attack.

Let's talk about your project. We secure your Wave, Paystack, Flutterwave and Stripe webhooks with HMAC signatures, idempotency and a status re-check. WhatsApp +221 77 596 93 33.

Tags:#webhook#signature#hmac#security#idempotency#payment
Share:

Mohamed Bah

Fondateur, Kolonell

Passionate about digital and entrepreneurship in Africa, Mohamed has been helping Sénégalese businesses with their digital transformation since 2020. Founder of Kolonell, he believes every SME deserves a professional and accessible online présence.