Why the integration layer is the weakest link

Payment gateways themselves are PCI-DSS Level 1 certified. Their infrastructure is hardened. But the moment you write code that talks to their API — initialising transactions, verifying callbacks, processing webhooks — you inherit responsibility for everything that happens on your side of the boundary. Most of the critical payment bugs we find during API security assessments are not in the gateway; they are in the integration code.

Nigerian fintechs move fast, and payment integration is often the first feature built. Speed pressure means corners get cut: webhook signatures go unchecked, amounts are trusted from the client, and secret keys end up in frontend bundles. Each of these is a direct path to financial loss.

Webhook signature verification: the non-negotiable

Paystack signs every webhook payload with HMAC-SHA512 using your secret key, placing the result in the x-paystack-signature header. Flutterwave uses a verif-hash header with a secret hash you define. Stripe uses HMAC-SHA256 with a webhook signing secret placed in stripe-signature. Despite the differences, the verification pattern is the same.

The three-step verification pattern

First, capture the raw request body before any JSON parsing. Any whitespace reformatting or key reordering will produce a different hash. Second, compute the HMAC using the raw body and your secret key with the correct algorithm (SHA-512 for Paystack, SHA-256 for Stripe). Third, compare the computed hash against the header value using a constant-time comparison function like crypto.timingSafeEqual() in Node.js. A naive string comparison (===) leaks timing information that an attacker can exploit byte by byte.

We covered the full verification flow in our webhook security deep-dive, but the critical takeaway is: signature verification must be a middleware, not an afterthought buried inside a controller. New routes and refactoring must not be able to bypass it.

Common Vulnerability

Client-side amount trust

In over 40% of the fintech pentests we conduct, the transaction amount sent from the frontend is trusted without server-side re-verification. An attacker can initialise a ₦100 transaction, intercept the callback, and have the system credit ₦100,000. Always re-verify the amount against your database record after the gateway confirms payment.

Server-side amount validation

After receiving a successful webhook or redirect callback, your backend must perform a verification API call (e.g., Paystack's GET /transaction/verify/:reference). Compare the returned amount, currency, and status against the original transaction record you stored when the payment was initialised. If any value differs, reject the transaction and flag it for review.

This is not optional. Without this step, an attacker who controls the client can manipulate the amount parameter during initialisation, or forge a webhook claiming a higher amount was paid. The gateway's verification endpoint is your single source of truth.

Idempotency: preventing duplicate charges

Payment gateways retry webhooks when your server responds with anything other than a 2xx status code. Network glitches, load balancer timeouts, and deployment rollouts can all cause your server to miss the initial delivery. Without idempotency, each retry processes the payment again — crediting wallets, triggering disbursements, or issuing receipts multiple times.

Use the transaction reference or event ID as an idempotency key. Before executing any business logic, check whether that reference has already been processed. Store processed references in a database table with a unique constraint, or use a Redis set with a TTL matching the gateway's retry window (typically 24–72 hours). Respond with 200 OK to acknowledge receipt even when skipping duplicate processing — otherwise the gateway will keep retrying.

Secret key management and rotation

Your Paystack or Flutterwave secret key is equivalent to a database password. If it leaks, an attacker can initialise transactions, verify payments, and manipulate your account. Yet we routinely find secret keys committed to Git repositories, stored in .env files deployed to production, or hardcoded in mobile app bundles.

Key rotation strategy

Store secret keys in a dedicated secrets manager — AWS Secrets Manager, HashiCorp Vault, or at minimum environment variables injected at runtime. Rotate keys on a defined schedule (quarterly at minimum) and immediately after any team member with access leaves the company. During rotation, support both old and new keys for a brief overlap window to avoid dropping in-flight webhooks.

For teams using CI/CD pipelines, ensure secret keys are injected via the pipeline's secrets store and never written to build artifacts or container images.

Are your payment integrations leaking secret keys or skipping server-side validation?

Book a Payment Security Audit

PCI scope implications by integration type

Not all integrations carry the same PCI-DSS burden. Understanding where cardholder data flows determines your compliance scope.

Redirect / Hosted page

Paystack Popup, Flutterwave Standard, Stripe Checkout. Card data never touches your servers. Lowest PCI scope — you only need SAQ A. This is the recommended integration for most Nigerian fintechs.

Inline / Embedded form

Paystack Inline, Stripe Elements. Card data is tokenised in the browser before reaching your server. You inherit SAQ A-EP scope — your page must be served over TLS and protected against XSS, since a compromised page could exfiltrate card data before tokenisation.

Direct API / Server-to-server

Charging tokens or processing raw card numbers via API. Full SAQ D scope. Your entire server environment is in PCI scope. Unless you have a dedicated compliance team, avoid this integration type entirely.

For a deeper breakdown of PCI requirements for Nigerian fintechs, see our PCI-DSS compliance guide.

Hardening checklist

If you are building a payment product in Nigeria, this is foundational work. The fintech security checklist covers these controls and more in an actionable format you can hand to your engineering team.

Related reading

Blog: Webhook security for payment platforms · The most dangerous API vulnerability · Rate limiting for payment APIs

Guides: PCI-DSS for Nigerian fintechs · Fintech security checklist · OWASP for fintech

Services: API security · Penetration testing