Data AnalyticsDomain analytics and business cases

Reconcile invoice, payment and refund records

PK
Pankit Kumar
Sr. Data Scientist at Parexel (a Goldman Sachs–backed company) · 20 September 2026 · 3 min read
Technically reviewed by Ishaan Sharma
In this article (5 sections)

Invoices describe amounts billed under an invoice contract. Payments and refunds describe money movement or attempts to move money. Credit notes adjust invoice value. These records are related, but they are not interchangeable, and subtracting the same economic adjustment in several places can create a false shortfall.

Build separate invoice and cash bridges, then explain the difference between them with allocation and timing evidence.

Inspect a deliberately imperfect teaching ledger

The synthetic billing invoices total 150,000 paise. A posted credit of 20,000 reduces the adjusted invoice amount to 130,000.

The payments include 150,000 of settled invoice-linked payments, one failed attempt of 10,000 and an unallocated settled payment of 7,000. The refund ledger includes a settled refund of 20,000 and a pending refund request of 5,000.

All records are synthetic. Status names are local to the fixture, and the example omits tax, fees, currency conversion and disputes. Its purpose is analytical reconciliation rather than a prescribed bookkeeping treatment.

Reconcile only the selected status and cutoff

sql
SELECT
 (SELECT SUM(amount_paise) FROM billing_invoices) AS invoiced_paise,
 (SELECT SUM(amount_paise) FROM billing_credits
  WHERE posted_at<'2026-02-01') AS credited_paise,
 (SELECT SUM(amount_paise) FROM billing_payments
  WHERE status='settled' AND occurred_at<'2026-02-01') AS settled_payments_paise,
 (SELECT SUM(amount_paise) FROM billing_refunds
  WHERE status='settled' AND occurred_at<'2026-02-01') AS settled_refunds_paise,
 (SELECT SUM(amount_paise) FROM billing_payments
  WHERE status='settled' AND invoice_id IS NULL
    AND occurred_at<'2026-02-01') AS unallocated_payments_paise;

The invoice bridge is 150,000 − 20,000 = 130,000. The cash bridge is 157,000 − 20,000 = 137,000. The 7,000 difference is unallocated settled cash, not unexplained invoice revenue.

python
from build_and_verify import database

db = database()
invoiced = db.execute('SELECT SUM(amount_paise) FROM billing_invoices').fetchone()[0]
credits = db.execute("SELECT SUM(amount_paise) FROM billing_credits WHERE posted_at<'2026-02-01'").fetchone()[0]
payments = db.execute("SELECT * FROM billing_payments WHERE occurred_at<'2026-02-01'").fetchall()
refunds = db.execute("SELECT * FROM billing_refunds WHERE occurred_at<'2026-02-01'").fetchall()
settled = sum(r[2] for r in payments if r[3]=='settled')
refunded = sum(r[2] for r in refunds if r[3]=='settled')
unallocated = sum(r[2] for r in payments if r[3]=='settled' and r[1] is None)
pending_refunds = sum(r[2] for r in refunds if r[3]=='pending')
db.close()
assert (invoiced,credits,settled,refunded,unallocated,pending_refunds)==(
    150000,20000,157000,20000,7000,5000)
assert settled-refunded-unallocated == invoiced-credits == 130000
print({'adjusted_invoices':invoiced-credits,'net_settled_cash':settled-refunded,
       'unallocated_cash':unallocated,'pending_refund_requests':pending_refunds})

The pending 5,000 refund remains a separate operational item. It has not reduced settled cash under this fixture's status contract. Stripe's refund API documentation distinguishes refund statuses; a production integration must map its provider's actual lifecycle rather than treating every refund record as completed cash movement.

Avoid subtracting the credit and refund twice

For B1, a 20,000 credit reduces the billed amount from 100,000 to 80,000. Its settled refund reduces net paid cash from 100,000 to 80,000. Those two ledgers now agree. Subtracting both the credit and the refund from invoice value would incorrectly reduce that invoice-side measure to 60,000.

The appropriate journal entries depend on the accounting system and transaction circumstances. The analytical requirement is to preserve each ledger's meaning and reconcile their relationships explicitly.

Check identities before accepting the bridge

Payment IDs and refund IDs should identify economic events, not webhook deliveries. A repeated notification must not create another payment. Conflicting payloads for the same identifier require investigation rather than arbitrary deduplication.

Refunds must link to the correct payment, and invoice allocation must not multiply money through a many-to-many join. For partial allocations, use a separate allocation table with amounts and verify that allocated totals do not exceed the applicable payment under the chosen rules.

An aggregate equality is necessary but not sufficient. Two offsetting errors can cancel. Reconcile per invoice or account, retain unmatched records and compare source-control totals as well as the final grand total.

Exercise: change the pending refund to settled after February 1. Show that the January snapshot remains unchanged while the later cash bridge requires a corresponding invoice adjustment or an explicitly explained timing difference.

NeuraPath's Data Analytics with Generative AI course connects SQL data modeling with financial operations. A good reconciliation explains status, timing and allocation before presenting a zero difference as success.

Continue learning

This article is part of the Domain analytics and business cases sequence. Use the neighbouring tasks when you need the prerequisite or the next application.

PK
Pankit Kumar
Lead Instructor, NeuraPath Academy

Pankit Kumar has 10 years in Data Science & AI, building and shipping production systems in regulated pharma and clinical environments. He is a freelance trainer at Boston Institute of Analytics, AnalytixLabs and Scaler, and has taught this material to thousands of working professionals.

This article is part of our Data Analytics with Generative AI programme — 3–4 months. The full analyst stack — Excel, SQL, Power BI and Python pipelines — then a generative-AI layer you can prove is right.

Explore Data Analytics with Generative AI
Counselling is free · no obligation

Not sure which programme fits?

Tell us your background and we will map it to the right entry point — including saying so when a cheaper programme is the better fit. A counsellor replies within one working day.