Payment incidents almost always share one shape: the server trusts the amount the browser sent. Anything coming from the browser can be modified by the user, so paying 100 won for a 100,000 won item is genuinely achievable.
What does re-verifying on the server actually mean?
When a user says they want to buy an item, the server looks that item price up in its own database and uses that figure to charge. The number from the browser is only for display, never for billing. After payment completes, the server should also ask the payment provider what was actually charged.
The rest of the payment checklist
- Use an established payment provider and never store card numbers yourself.
- Run the whole flow, including refunds, in test mode before launch.
- Verify that webhook calls genuinely come from the payment provider.
- Ensure a duplicated webhook does not deliver the product twice.
- Have a written refund policy and a process to execute it.
- Complete business registration and e-commerce filing where required.
Why is payment the one thing not to build yourself?
Other features can be fixed after the fact. Payments cannot: a mistake either sends money out or fails to bring it in, immediately. And because the person harmed is your customer, you lose trust along with the money. It is the one area where a single incident costs more than building it properly.
Treat every value from the browser as untrusted: amount, quantity, discount rate, and user tier alike.