Availability: Taking on new projects

A payment gateway declining everything, for several unrelated reasons

Client
Luxury furniture retailer
Where
North Macedonia
When
2026
Type
Long-running client

The problem

A bank payment integration failing in production with declines that produced no usable error, on a store where the displayed currency and the base currency differ.

A gateway that fails cleanly is a morning’s work. This one failed in several unrelated ways simultaneously, and each fix revealed the next fault underneath.

What was actually wrong

  1. A strict type comparison treating a numeric zero and a string zero as different, which sent the wrong currency identifier to the bank on every request.
  2. A store key that had been changed on the bank’s side without notice. That one cannot be found by reading code — it was isolated by eliminating every other variable until nothing else remained.
  3. Response signature validation rebuilt incorrectly. The signature has to be reconstructed from the named fields the bank lists, looked up individually against the posted values and joined with separators — not taken from the pre-assembled string that looks like it should serve the same purpose.
  4. The cart being emptied when a payment failed, so a customer whose card was declined had nothing left to retry with.
  5. Payment metadata written in a mode that refuses to overwrite, so a retry could never replace the data from the failed attempt.
  6. A guard against processing an already-paid order that checked correctly and then carried on anyway, because it was missing a return.
  7. Failed payments redirecting to a page with no way forward, instead of the page that lets a customer try again.
  8. A failure notification email carrying the success email’s subject line, so customers whose payment had been declined were told it had succeeded.

Two things worth generalising

The bank’s own documentation recommended a signature version its deployment does not support. Vendor documentation describes the product, not the instance you have been given access to. When the documented approach fails at the first request, the documentation is a hypothesis like any other.

And one of the values that looked most obviously like a bug — a zero where a currency code belonged — turned out to be correct, because in this system it means use the merchant’s configured default. Not every anomaly is a fault, and changing one you have not understood is how a three-fault problem becomes a four-fault problem.

The outcome

The gateway restored to full working order, with every distinct fault identified and fixed rather than worked around, including two that only appeared once the earlier ones were gone.

Describe the symptom. I will tell you what it usually means.

Every enquiry gets a reply within one working day.