The specialist third party that actually moves money: takes card or wallet details, charges them, and confirms the result.
Why it exists
Taking money means handling card data under strict rules, talking to banks, and carrying fraud and compliance risk a normal product cannot safely absorb. Building this in-house is a legal and security minefield. A payment gateway exists to move money through a specialist's systems, so you can charge customers without touching the most dangerous parts yourself.
How it actually works
When a customer pays, your app hands the payment details to a gateway (Stripe, SSLCommerz, bKash) rather than touching the card itself. The gateway talks to the banks, performs the charge, and returns success or failure.
Critically, the sensitive card data flows to the gateway, not your servers, which keeps you out of the riskiest compliance territory. You get back a token or a receipt, not the raw card number.
A senior PM walks you through it
A junior PM, stuck
Payment failures jumped about 3x during Friday lunch peak, and the dev pasted the gateway's decline response asking whether we should retry these. I could not tell them, because I cannot tell a plain bank decline from a fraud block. They look like the same failure to me, and retrying the wrong one seems risky.
You are right to hesitate, because those two declines want opposite handling. A payment gateway is the specialist that talks to banks for you, and when it says no, the reason field tells you which kind of no it is. I pulled the real charge TiffinBox sends and two decline responses that look almost identical. One field separates them, and that field decides retry versus stop.
One charge to the gateway, and two declines that look alike
What TiffinBox sends the gateway
1:1
2:
3{"amount":649,"currency":"BDT",
4"source":"tok_1a2b3c","order_id":"o_5512"}
Decline A
51.1402
6{"status":"declined",
7"code":"insufficient_funds",
8"decline_type":"issuer"}
Decline B
91.1402
10{"status":"declined",
11"code":"risk_check_failed",
12"decline_type":"fraud"}
Click a step to see the lines it points at.
Mistakes I've seen
Auto-retrying every decline. A fraud block retried looks like an attack and can freeze the account. Split retry logic by decline_type before you build it, not after a spike.
Showing the customer one generic "payment failed" for all cases. "Not enough funds, try another card" and a quiet fraud stop need different messages. The reason code is what lets you write the right one.
Assuming TiffinBox holds the card because it took the payment. It holds a token; the gateway holds the card. Getting this wrong in a security answer overstates your own risk and compliance load.
Treating a gateway timeout as a decline. A timeout means no answer, so the charge may or may not have gone through. That is the case where a blind retry double-charges, which is why it needs an idempotency key, not a plain retry.
Answer the dev with: "Retry the issuer declines like insufficient_funds, but never auto-retry risk_check_failed, that is a fraud block. And for the peak-time timeouts we need an idempotency key so a retry cannot double-charge." You read the decline_type and split the handling. That is reading a payment gateway.
Where a PM meets this
Gateway choice affects fees, which payment methods you support, and success rates in your market; all product-relevant.
Payment failures have many causes (bank declines, network, fraud checks); designing clear failure and retry flows is real product work.
Hear it in a meeting
"bKash success rates are higher locally, let's add it alongside cards."