Skip to main content
FomiVIP
Service Cases

BiMBA Alumni Donation Page: Getting Payment Callbacks Right

The donation form took half a day; the payment callbacks took the rest. A re-sent notification recorded one gift twice — fixed with a unique index on merchant order number, signature first. A 40-minute-late callback led to a polling job. Finance gets a 7-column Excel every day at 5 p.m.

June 28, 2023Payment IntegrationCase StudyReconciliation

The donation page itself took half a day: a few preset amounts, a custom field, name, anonymous toggle, one message line — 5 fields. The rest of the time went to wrestling with payment callbacks.

Two Problems With Callbacks

In the first version of our payment notification endpoint, we updated the order status and recorded the donation on receipt. Day three after launch, trouble: the same donation was recorded twice. The logs showed the provider had re-sent the same notification, and we hadn't made the handler idempotent.

The fix: a unique index on the merchant order number, with duplicate notifications returning success without writing again. One trap here: verify the signature before deduplicating — don't return success just because you've seen the number before; it might be forged.

The second problem was messier: one notification arrived 40 minutes late. The user had long since seen "payment successful" on the page, the backend still showed unconfirmed, and finance's daily summary was missing the gift.

Polling Instead of Waiting

Waiting for callbacks alone isn't enough. We added a scheduled job that scans every 30 minutes for orders "created but unconfirmed" older than 10 minutes and actively queries the payment provider's order-status API — their result wins.

Both the polling job and the callbacks write to the same donations table, with that unique index blocking duplicates. Whichever arrives first wins — that's the key.

We also gave finance a manual "backfill" entry point: look up by merchant order number, permission required, every operation logged. It's been used twice since launch — both times the provider had genuinely lost the notification.

That Daily Afternoon Spreadsheet

What finance needs is something they can reconcile against, not an admin page. Every day at 5 p.m. we export an Excel: merchant order number, donor, amount, payment method, payment time, anonymous flag, message — 7 columns, sorted by payment time. Anonymous rows say "Anonymous" for donor, but the order number is still there, so everything reconciles.

The first week surfaced 3 discrepancies: 2 late callbacks and 1 user who paid and instantly canceled, leaving states out of sync. All were caught by the polling step.

June 28

On launch day, the first donation was 200 yuan with a message: "Buy books for the younger students." We screenshotted that row — didn't post it to the group chat, just saved it in the project folder.

Later a "request a receipt" checkbox was added to the page — fields went from 5 to 6. A tiny change; the real work was two extra columns in finance's export, which took an hour.

Consulting · Free initial chat

Need advice for your scenario?

Tell us your business context and current systems, and we'll give an actionable approach.

Contact us

Mon–Fri 9:00–18:00 · We respond on business days within one business day.

WeChat (Business Only)
WeChat (Business Only)二维码

Scan and add our WeChat for consulting

Or fill out the requirements form