By Editorial Team, reviewed by Editorial Team (approved by site owner) · Published · 1 min read
Payments are asynchronous and external. Most defects come from assuming otherwise. These are the failure modes we design for.
Duplicate webhooks
Providers retry webhooks. If each delivery credits a wallet, a retry credits twice. Store the provider event identifier and make processing idempotent. The idempotent-request concept in the Stripe documentation below describes the same principle for API calls.
Lost webhooks
Webhooks can fail to arrive. Do not rely on them alone: poll or query pending payments after a delay, and reconcile against settlement files.
Out-of-order events
A "failed" event may arrive after "succeeded", or the reverse. Model payments as a state machine with allowed transitions and ignore or flag illegal ones.
Timeouts
When a call to a provider times out, the outcome is unknown. Mark the payment as pending and resolve by querying the provider, never by retrying blindly.
Partial and reversed payments
Refunds, chargebacks and partial captures must flow into the ledger as their own entries, not as edits to old ones.
Reconciliation
Match provider reports against ledger entries daily. Investigate every mismatch category; recurring mismatches usually point to a design flaw.
Card data scope
Using provider-hosted payment fields reduces how much card data your systems touch, which narrows the scope of PCI DSS obligations. Confirm your specific requirements with the PCI SSC guidance and your assessor.
Availability varies
Which methods are available depends on the provider, your business model and your markets. Confirm with each provider rather than assuming.

