Stripe (or any equivalent processor) handles the hard cryptographic and compliance parts of payments — your job is to integrate it without reopening the problems it already solved. Read Payment System Basics@markdowners/payment-system-basics first; everything below assumes it.
Client/server split
Only ever use a publishable/public key in client-side code; the secret key must never leave the server, never be sent to the client, and never be committed to source control.
Create the PaymentIntent (or equivalent) server-side, computing the amount from your own database — never accept an amount from the client and pass it straight to the charge-creation call.
Elements / hosted fields
Use the processor's client-side Elements/hosted-fields SDK for collecting raw card data so it never touches your server — this is what keeps you out of full PCI-DSS scope.
Handle 3-D Secure / SCA challenges as a normal, expected flow (requires_action status), not an edge case — in regulated markets (EU, UK, India) a large share of legitimate cards will trigger it.
Confirming payment
Never mark an order as paid purely because the client-side confirmation call succeeded — a client can lose network connectivity, close the tab, or lie. The authoritative signal is the server-to-server webhook event (payment_intent.succeeded or equivalent).
Treat the redirect-back-to-your-site step as a UX convenience only ("we're processing your payment"), not a fulfillment trigger.
Test mode
Develop and test exclusively against test-mode keys and the processor's published test card numbers (including decline codes, insufficient-funds cards, and 3DS-challenge cards) — never use real card numbers in a development environment even "just to check."
Keep test-mode and live-mode keys in clearly separated environment variables so a misconfigured deploy can't accidentally process real charges against test infrastructure or vice versa.
Amounts and currency
Pass amounts in the processor's expected minor unit (cents) and always pass an explicit currency — verify the zero-decimal-currency list (JPY, etc.) before assuming ×100 universally.
Errors
Map processor decline codes to specific, actionable user messages ("Your card was declined — try a different card" vs. "insufficient funds") rather than a single generic "Payment failed."
Log the processor's request ID with every payment-related log line — it is what the processor's own support team will ask for first when debugging a specific transaction.
Webhooks
Always verify the webhook's signature, and always treat webhook delivery as the trigger for fulfillment, never the client-side confirmation callback.
Comments (0)
Sign in to comment. Sign in
No comments yet. Be the first to add one.