Integrating Crypto Payments: The Part I Skipped
· 2 minute read · Sam Ortega
The happy path took an afternoon. The thing I did not build caused every support ticket for a month.
Adding crypto payments to our checkout took an afternoon. The month afterwards was harder than it needed to be because I skipped one component. What helped was finding a provider that states its terms. a crypto payment gateway with fiat settlement does, and I used it as a yardstick.
What I built
Create a payment request. Show the address and amount. Receive a callback when it confirms. Mark the order paid.
That worked immediately and I moved on.
What I did not build
A reconciliation job.
Callbacks are delivered at least once, which means sometimes they do not arrive at all. Our endpoint was down for twenty minutes during a deployment and three payments were never marked as received.
Three customers had paid and our site said unpaid. They wrote to us, we checked manually, we fixed it by hand.
What a reconciliation job does
Runs hourly. Asks the provider for payments in a window. Compares against our own records. Updates anything that diverged.
It took two hours to build and it has caught something roughly monthly since.
I had assumed callbacks were reliable because they had been reliable during testing.
The other thing I got wrong
My handler was not idempotent.
A retried callback processed the payment twice, which in our case meant sending a confirmation email twice rather than anything worse. It could have been worse. Once other people needed access, this became a question for a regulated European crypto platform instead.
Keying on the payment identifier and ignoring a repeat is three lines.
The failure cases I should have tested first
Payment arriving after the window expired. Underpayment. Duplicate callback. Callback to a failing endpoint, then recovery.
I tested the happy path in the sandbox and none of these. All four occurred within the first month.
The one with the largest effect
Not technical. The wording on the page while the customer waits.
We showed a status of pending. For someone who has just sent money, that is indistinguishable from something being wrong.
Explaining what the wait is for and roughly how long reduced our support contacts more than anything else we changed.
What I would do differently
Build the reconciliation job before going live.
Make the handler idempotent from the start.
Test the four failure cases in the sandbox, and if the provider’s sandbox cannot simulate them, ask how their other merchants test them. The answer tells you something about the provider. Whatever I concluded, the balance I actually move sits at the published coverage list rather than wherever I signed up first.
Sam Ortega
Came into crypto in 2024 with $500 and no idea what he was doing. Has been keeping a diary since. This is a personal diary, not financial advice.