For about seven years at a global payments company in Lahore, I built systems that moved other people's money. It is easy, in that work, to start seeing transactions as rows and volumes and throughput. The thing that kept me honest was a correction I had to keep making: a declined card is not an error code. It is a person standing at a till, in front of other people, watching the machine say no.
Somewhere on the other end of every authorisation was a human being who had assumed, reasonably, that the money would just be there. At a petrol pump with a full tank already pumped. At a hospital counter. At a grocery till with a week of food on the belt. We were not processing transactions. We were keeping promises that people did not even know they were trusting us to keep.
Every Number Would Become a Person
Part of what we did was make card numbers. Not store them. Make them. Every card a programme issued needed a number that was unique, valid, and impossible to guess, and at the volumes a payment processor works in, that is a real engineering problem rather than a clerical one.
A card number is not random digits. The first several identify the issuer and the programme, the BIN. The final digit is a checksum, the Luhn digit, that catches a mistyped number before it ever reaches a network. Everything in between has to be generated so that no two live cards ever collide, across millions of them, and so that no one can sit down and predict the next one. We generated them with what we called the Wells algorithm, and we watched the conflict rate climb as a BIN's space filled up. Past roughly thirty percent collisions, generation slowed to a crawl and the odds of a clash grew uncomfortable, so we would switch to a fresh BIN before any customer ever felt it.
It is abstract work right up until you remember what each output becomes. Every number that survived generation would, weeks later, be embossed on a card in a real person's wallet, tapped at a checkout by someone who had no idea any of this had happened and no reason to care, as long as it worked.
Guarding the Whole Person
A card number was only the beginning of what we held. Behind it sat everything that made a cardholder a specific human being: their PIN, the family of card verification values (CVC1 on the magnetic stripe, CVC2 printed on the card, CVC3 for contactless), and the ordinary, devastating details – name, address, date of birth. We ran a set of Data Vault services whose entire purpose was to guard all of it, with cryptography as the baseline rather than an afterthought. Hardware security modules held the keys and performed the encryption, so the secrets never sat in the open. Sensitive values were tokenised, so most of the platform worked with stand-ins that meant nothing if they ever leaked. The whole of it lived under the discipline of PCI.
It is tempting to call that "protecting data". It never felt like data. It felt like protecting people who would never know my name, from harms they would never see coming. The vault was not a compliance checkbox bolted to the side of the platform. It was the same thesis in a different form: there was a person behind every field.
The Students Who Were Counting on It
Another system I worked on moved money across borders. One programme I have never forgotten handled transfers for Brazilian-government scholarship students, young people studying far from home who depended on that money arriving, on time, to pay rent and to eat. For them a transfer was not a feature in a product. It was the difference between an ordinary week and a frightening one.
Cross-border money is fragile in a way domestic payments are not. It passes through more hands, more networks, more institutions, and every handoff is a place it can stall. Visa and Mastercard hold processors to strict service levels, and we tracked them closely. But the real specification was never the figure on a dashboard. It was a student in another country refreshing a balance, hoping it had cleared before the landlord asked. Latency and availability are abstractions until you can name one person on the other side of them. Then they stop being abstractions entirely.
I have never found a better discipline than this: before you optimise a system, name one real person who is harmed when it fails, and build for them. The metrics tend to take care of themselves once you do.
Build Like Someone Is Waiting
The systems were high-throughput, multi-threaded, and held to sub-second responses at high availability, because a payment that arrives late is, to the person standing at the terminal, a payment that failed. We learned to treat correctness as non-negotiable and silence as the enemy, because the cost of being quietly wrong was never a bug ticket. It was someone's bad day, or something worse than a bad day.
Seven years of that changes your defaults. I stopped thinking of throughput as a number to maximise and started seeing it as a queue of people, each one waiting for a single specific thing to work. That reframing has outlasted payments for me by more than a decade. It is the most useful thing the domain ever gave me, and I have carried it into every system since, none of which felt quite as unforgiving, and all of which were better for being built as if they were.