Trust the webhook, never the redirect
Customers can bookmark, share, or be redirected by a flaky browser. The webhook is the only ground truth. Don't fulfil an order on success_url alone.
Validate webhook signatures
Every webhook is HMAC-SHA256 signed with your endpoint secret. Reject any delivery whose signature doesn't match — without this check, anyone who knows your URL can mark orders paid.
Make the webhook handler idempotent
We retry deliveries on non-2xx responses, and at-least-once means you will sometimes get the same event twice. Look up the event id before acting; ignore if you've seen it.
Use idempotency keys on every money-moving POST
Generate a fresh UUID per logical operation (per order, per refund, per transfer). On retries, send the same key — the server returns the original response instead of doing the work twice.
Keep secrets in a vault, not in env files committed to git
At minimum, use a .env file that's in .gitignore. Better, use your platform's secret manager (AWS Secrets Manager, Doppler, 1Password). Rotate on every offboard.
Use the sandbox to test failure modes
Don't wait for production to discover what happens when a customer cancels mid-flow. The sandbox lets you simulate every state explicitly.
Cap your timeouts
Set a connect timeout of 5s and a read timeout of 30s. Anything longer is almost certainly a hung connection — fail fast and let your retry loop handle it.