Build1 distinct publisher3 min readPublished
A dev.to walkthrough on payment reconciliation separates three places a webhook update can be lost, and only one of them sits on the provider's side of the wire. The other two are yours to notice and repair, on your own schedule.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
Follow any of these and your For You feed starts watching them — no settings page required.
build
Three ledgers, one payment: reconciliation breaks because the model picked a winner1 distinct publisher
build
Disabling Submit Fixes the Click, Not the Lost Response1 distinct publisher
build
Reserving the idempotency key before the gateway call is what wins the race1 distinct publisher
build
A recorded cutoff and an operation key make the second delete delivery a no-op1 distinct publisher
The third loss point is where the design pressure comes from: the business effect lands but the row that records it does not [5]. From outside your process, that is indistinguishable from a webhook that never arrived, and when the provider retries the same event later [6], the payload carries no way to separate "apply this" from "you already did". The receiver has to answer that question, which is why the application-side inventory in the dev.to piece includes a `processed_webhooks` table next to `payment_transactions`, `subscriptions`, `orders`, `invoices` and `wallets` [8]. That is the table nobody creates until the second incident.
The loop the article proposes is modest, and I think it is right: keep webhooks for near real-time updates, keep enough local state to know which records are unresolved, then periodically ask the authoritative source what happened and apply the missed update through the same path the webhook would have used [11]. Three conditions have to hold before that transfers to your stack. The handler must be safe to run twice, which the author treats as a design requirement rather than a nicety [13]. The schema must be able to name the unresolved set, which is the local-state half of the same recommendation [11]. And the provider must expose a lookup keyed by something you stored when you created the charge. That last condition is absent from the source material, and it is the one that varies most between providers. If the only handle you kept was the provider's id, and you lost it in the timeout, the sweep has nothing to join on.
Ordering is the other half of the subsystem. A delayed refund event must not leave a local record successful forever, and a missed failure must not keep access granted forever [12]. Both examples are about precedence rather than delivery: you need a rule for which state wins when an older event lands after a newer one, because arrival order carries no information about the order of the facts. The piece is blunt that this is ordinary distributed-systems behaviour and not an edge case to defer once money is in the path [14], and it extends the argument past the database boundary, where a committed transaction can still be followed by a failed cache update, notification or downstream job [7].
What is available here is framing rather than a specification. The outline promises sections on designing the flow, idempotency, reconciliation for payment providers, and observability with manual recovery [17], and the text stops before the flow itself. The framing is the part worth arguing about anyway, and it holds. If reconciliation means comparing state across a boundary and deciding what should be true now [3], then it owns a schedule and an owner, like any other subsystem in the diagram.
Ranked by verification strength, evidence, and original report placement.
The article states its scope as why webhooks are not enough, how provider payments can be matched to internal records, how to handle out-of-order states, and how to build a safe, idempotent reconciliation flow.
The article's section list includes Designing a Reconciliation Flow, Idempotency in Reconciliation, Reconciliation for Payment Providers, and Observability and Manual Recovery.
The typical payment happy path: a user initiates a payment, the provider processes it, a webhook arrives, and the application updates the corresponding subscription, order, invoice or wallet.
Servers go down, webhooks arrive late, workers fail and requests time out after money has already moved; when that happens the provider may have the correct payment state while the application does not. A queue may accept a job while the worker fails before applying the business update.
Reconciliation is defined as the process of comparing the state of a payment-related operation across systems and deciding what should be true now.
A webhook is still a message, and like every message it can be delayed, duplicated, dropped or processed partially.
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 30, 2026
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
One author, checkable by reason alone
Everything rests on a single dev.to walkthrough, and it cites nothing — no provider documentation, no incident write-up, no code, no measurement. What keeps the number from being lower is the nature of the claims: the three loss points and the two state inventories are the kind of assertion a reader verifies by thinking, not by trusting. What holds it down is that the copy breaks off mid-sentence before the idempotency and observability material it promised, so the practical half of the argument is unexamined.
Nothing here was shipped
No release, deployment, benchmark or usage disclosure exists to count. dev.to names no provider, no library and no team that runs this pattern, so any adoption figure would be invented rather than observed.
Claims sized to what is being said
The piece never claims novelty, never says reconciliation is solved, and never implies its pattern is cheap. It calls post-payment failures ordinary distributed-system behaviour, which is the correct and unglamorous framing. Our own headline sharpens the three-loss-point split into something that reads like a finding; in the source it is simply careful exposition.
Nothing is being sold
Look for the pitch and it isn't there: no processor is named, not one SDK or dashboard is linked, no employer or client appears. The identifiers and record types are generic enough to fit any provider. What remains is the ordinary developer-platform incentive to publish and be read, which shapes length and section structure far more than it shapes the argument.
Safe precisely because it is uncontroversial
We are confident about what the story says and confident the reasoning is sound; we have no basis to judge whether the recommended repair loop survives contact with a real provider's API limits. Single-sourcing usually caps confidence hard, and it does here — but nothing in the argument depends on a number only the author can see, which is why the reading sits in the middle rather than the basement.