DEV Community

Payneteasy
Payneteasy

Posted on

Void vs refund isn't a status check, it's a race against batch cutoff

Had a cancellation flow that called void() first, fell back to refund() if void failed. Worked in testing because nothing ever settled fast enough to matter. In production, the acquirer's batch cutoff was 11:47 PM local, and any transaction authorized before that got swept into settlement by midnight. Cancel at 11:50 PM on a transaction from 11:30 PM and void returns a decline, not because the request is wrong but because the underlying auth no longer exists to void, it's already a settled charge.

The fallback to refund worked, but only after we added a specific error-code check for that scenario instead of treating every void failure as a hard error. Before that fix, void failures near cutoff were logged as customer-facing errors even though the refund fallback silently succeeded three seconds later.

The part that surprised me: cutoff time isn't fixed per acquirer, it can shift with daylight saving changes or get moved during processor maintenance windows without much notice. We ended up caching it from the last successful settlement report response instead of hardcoding a time.

Anyone tracking cutoff time dynamically, or is everyone just hardcoding a conservative buffer and eating the occasional double-code-path failure?

Top comments (0)