Outcomes

Your Stripe Dashboard Says Paid. Your Database Says Otherwise. Here's the Gap.

Revenue reconciliation is the kind of problem that feels like it should be solved. You have Stripe. You have a database. Both record everything. How hard can it be to verify they agree?

Harder than anyone wants to admit. And the cost of not doing it is not just revenue leakage — it is the slow accumulation of customers who paid and did not receive what they paid for, quietly downgrading their opinion of you, quietly telling other people.

HookTunnel's Stripe reconciliation closes the gap between "Stripe says paid" and "your database says applied." It works at the level where the gap actually lives: the webhook handler.


The CFO Meeting

It is a Thursday afternoon. Your VP of Finance has pulled a report showing seven customers on Pro subscriptions in Stripe who do not have Pro-tier access in the database. They want an explanation for the board. The customers have been on these plans for between four and twelve days. Some of them have probably noticed and are too polite to say anything. Some of them are about to churn.

The old answer to this question involves a forensic exercise that takes the better part of three days. You pull the Stripe payment records. You pull your webhook delivery logs. You attempt to correlate event IDs across two systems that do not naturally speak to each other. You dig through application logs trying to find evidence that the handler ran and what happened when it did. You probably find something — a brief period of elevated database latency, a deploy that happened to coincide with a batch of webhook deliveries — and you patch together a story you are sixty percent confident in.

Then you fix the seven customers manually. In production. With raw SQL. Hoping you get the right user IDs.

Then you write a postmortem that says "we will improve our monitoring" without specifying what that monitoring will actually tell you.

The new answer takes twenty minutes.

You open HookTunnel's reconciliation dashboard. You select the last fourteen days. Seven events appear in the Paid, Outcome Unknown bucket — customer.subscription.updated events that were delivered (Stripe confirmed it, your server returned 200) but for which no confirmed receipt ever arrived. All seven are clustered in a four-day window from twelve days ago.

You click into the window. The timeline shows a sharp spike in Applied Unknown events that corresponds exactly to the four-day period. You check the circuit breaker history — there was a database connection storm during that window. Your handler was returning 200 before the database write, and the write was quietly failing due to pool exhaustion.

You already know the fix was deployed ten days ago. The database writes work fine now. You click Replay All on the seven events. Guardrailed replay checks each one — none have received a confirmation receipt, so all seven are eligible. You execute. Receipts arrive for all seven within thirty seconds. They flip to Paid, Applied Confirmed.

You go back to the VP of Finance. "Seven customers were affected during a four-day window twelve days ago due to a database connection configuration issue. The fix was deployed ten days ago. All seven customers now have correct access. I have an audit trail showing the replay and confirmation for each one."

That is what finance-grade accountability looks like. Not a story you patched together. A provable record.


How Reconciliation Works

HookTunnel's reconciliation engine compares Stripe event records against the outcome receipt state for every matching webhook delivery. Events are sorted into four buckets:

Paid + Applied Confirmed

The happy path. Stripe recorded a successful payment event. Your webhook handler delivered. A signed receipt arrived confirming the database write committed. These events require no attention.

Paid + Applied Unknown

The gap you need to investigate. The payment succeeded, the webhook was delivered, the handler returned 200 — but no confirmation receipt ever arrived. The outcome is unknown. This could be a silent failure, a handler without receipt code, or a receipt POST that failed independently. These events are the primary focus of reconciliation.

Paid + Applied Failed

Your handler sent an explicit failure receipt. The write did not occur. These events are unambiguous — the application code confirmed failure. Replay them directly from the reconciliation view.

Paid + Not Delivered

Stripe registered a payment event but HookTunnel never received the delivery. This typically indicates a webhook configuration issue, a dead endpoint, or a Stripe retry that exhausted its attempts. These need to be sourced from Stripe's event API and injected for replay.

The time window selector defaults to the last 30 days and adjusts to your data retention tier. Drill down into any event to see the full timeline: when Stripe fired it, when your handler received it, what the handler returned, when (or whether) the receipt arrived, and every subsequent action taken.


This Requires Receipts — And That Is the Point

Reconciliation tools that assume "delivered equals applied" are telling you a comfortable lie. Stripe's own reconciliation reports operate at the payment level — they tell you whether the charge succeeded or failed at Stripe's infrastructure. They have no visibility into whether your application code processed the resulting webhook.

HookTunnel's reconciliation is meaningful because Applied Confirmed is provable. When an event shows as Paid + Applied Confirmed, that confirmation came from a cryptographically signed receipt that your application code sent after the database write committed. It is not an inference. It is not a heuristic. It is your code saying, in a verifiable message: this happened.

If you do not yet have receipt code in your handlers, events will land in Applied Unknown rather than Applied Confirmed. You still get the reconciliation view — you can still see the gap between paid events and confirmed outcomes. You simply cannot distinguish "worked but unverified" from "silently failed." Adding receipts to your handlers is the upgrade path from visibility to proof.


The Audit Trail

Every action taken in the reconciliation view is recorded in HookTunnel's immutable audit log:

  • Replay: timestamp, actor, which events were replayed, guardrail decisions for each, outcome receipts received
  • Trace: timestamp, actor, which investigation was opened
  • Manual Resolution: timestamp, actor, resolution note (required), reason code selected

The audit log is append-only. You cannot delete entries. You cannot edit notes after submission. When your VP of Finance asks for documentation of how a gap was closed, you export the audit log entry. It shows who did what, when, and why.

This matters in regulated industries where financial operations require evidence of remediation. It also matters when a customer disputes a charge and you need to show that their access was provisioned correctly and on time.


The Gap Workflow

Each event in the Paid + Applied Unknown or Paid + Applied Failed buckets has three available actions:

Replay

Triggers guardrailed replay for the event. The replay engine checks the current outcome state before executing — if a receipt has arrived since the reconciliation view loaded, the replay is skipped. After replay, the view refreshes with the updated outcome state. If a new receipt arrives after replay, the event moves to Applied Confirmed automatically.

Trace

Opens an investigation for the event. HookTunnel links the webhook delivery timeline, the receipt history, and any related events from the same customer or subscription into a single investigation view. You can add notes, tag the investigation, and share it with your team. The investigation persists — you are not reconstructing context every time someone looks at it.

Resolve

For events where replay is not appropriate — the customer cancelled their subscription before the fix, the event is stale beyond your retention window, or you have confirmed the database is correct through another mechanism — manual resolution closes the gap. A resolution note is required. The note and actor are recorded in the audit log. The event moves to a Resolved state that is distinct from Applied Confirmed; your reporting can distinguish "confirmed by application code" from "confirmed by human review."


What Stripe's Reconciliation Report Cannot Tell You

Stripe provides a reconciliation report through their Finance Automations feature (Sigma). It is excellent at the payment layer: successful charges, failed charges, refunds, disputes, payout timing. It knows whether Stripe processed the payment correctly.

It knows nothing about what happened in your application code after the webhook landed.

Whether your database accepted the write, whether the transaction committed, whether the async job that provisioned access to your Pro features actually ran — Stripe has no visibility into any of this. From Stripe's perspective, a 200 response from your handler means success. Full stop.

HookTunnel reconciles at the layer Stripe cannot see: the business logic layer. The question it answers is not "did the payment succeed?" (Stripe answers that) but "did your application apply the payment?" Only your application can answer that question, and HookTunnel is the infrastructure that captures and verifies the answer.


FAQ

Does reconciliation work with all Stripe event types?

Reconciliation is configured per event type. You define which event types are "payment events" for your integration. By default, HookTunnel watches customer.subscription.created, customer.subscription.updated, invoice.payment_succeeded, and checkout.session.completed. You can configure this list in your hook settings.

What if I have thousands of events in the gap?

Reconciliation handles bulk operations. You can select all events in a bucket and replay or resolve them as a batch. Guardrailed replay operates on each event individually during batch execution — if some events already have receipts, they are skipped automatically. The batch size limit is 500 events per operation; larger backlogs are processed in sequential batches.

How far back can I reconcile?

Time window is limited by your data retention tier: 24 hours for Free, 30 days for Pro, 90 days for Team, 1 year for Enterprise. If you need to reconcile events older than your retention window, you can import event IDs from Stripe's API and HookTunnel will look up what it has.

What if the gap is not a webhook issue — the data was correct already?

Use manual resolution with the reason code "Outcome confirmed by other means." Include a note describing how you verified it. The event moves to Resolved, not Applied Confirmed — keeping the distinction clear in your audit trail. Automated reconciliation will not flag it again.

Can I export the reconciliation report?

Yes. Export to CSV or JSON from any reconciliation view. The export includes event IDs, event types, customer IDs, outcome states, timestamps, and any resolution notes. The format is compatible with standard accounting software.

Is reconciliation real-time?

Reconciliation state updates in real time as receipts arrive. When you replay an event and a receipt comes back, the dashboard refreshes without a page reload. For batch reconciliation of historical periods, you can trigger a reconciliation run that processes the full window against current receipt state.

Start reconciling your Stripe payments

See which payments resulted in confirmed outcomes — and close the gaps.

Get started free →