Integration pattern
Reviewed 14 October 2026
A job that finds what the webhooks missed or doubled.payment reconciliation automation
Webhooks, imports and typing all feed the books, and any can miss or double. A job compares the books with the bank each night.
The demo matches bank lines to invoices in ERPNext. It does not show a webhook.
Use it when
- Money is recorded in two places by different routes, such as a gateway and the ledger.
- A missed or doubled event would not be noticed until month-end.
- More entries arrive than a person can match by eye in one sitting.
Skip it when
- You reconcile a few entries a month. ERPNext's manual Payment Reconciliation tool is enough.
- The cause is a handler that drops events every day. Fix the handler; the job is the net, not the repair.
- There is no outside record to compare with: no statement, no settlement list.
Try it
Run the reconciliation job
A sample ledger and a sample statement with five planted gaps. Run the job and see what is left for a person. Sample data. Not a measurement.
When it runs
Matched (4)
Same reference and amount.
Probable: needs a person (1)
Same amount and day, no reference.
₹4,100, first on the list 17 Oct. Confirm it is pay_A7, then add the reference.
Exceptions (4)
Each with what to check.
| What | Reference | Amount | What to do | First on the list |
|---|---|---|---|---|
| Booked twice | pay_A4 | ₹3,200 | Cancel the duplicate receipt. Check the webhook handler for a missing key. | 16 Oct |
| Short or over by ₹50 | pay_A5 | ₹9,700 | Ask the gateway why the settlement is short before you adjust anything. | 17 Oct |
| Never booked | pay_A6 | ₹6,400 | Create the receipt. Then find why the webhook missed it. | 17 Oct |
| In the books, not on the statement | pay_A8 | ₹2,000 | Wait for the next statement. If it is still missing, check the payment. | 18 Oct |
The books
Eight receipts booked by webhook, 14 to 17 October.
| Reference | Amount | Day |
|---|---|---|
| pay_A1 | ₹12,000 | 14 Oct |
| pay_A2 | ₹8,500 | 14 Oct |
| pay_A3 | ₹15,000 | 15 Oct |
| pay_A4 | ₹3,200 | 15 Oct |
| pay_A4 | ₹3,200 | 15 Oct |
| pay_A5 | ₹9,750 | 16 Oct |
| none | ₹4,100 | 16 Oct |
| pay_A8 | ₹2,000 | 17 Oct |
The statement
Seven lines: the outside record.
| Reference | Amount | Day |
|---|---|---|
| pay_A1 | ₹12,000 | 14 Oct |
| pay_A2 | ₹8,500 | 14 Oct |
| pay_A3 | ₹15,000 | 15 Oct |
| pay_A4 | ₹3,200 | 15 Oct |
| pay_A5 | ₹9,700 | 16 Oct |
| pay_A6 | ₹6,400 | 16 Oct |
| pay_A7 | ₹4,100 | 16 Oct |
How long senders keep trying: Frappe Webhook: three tries, pauses of 1 s and 4 s. Shopify: 8 tries over 4 hours. Razorpay: 24 hours. Stripe: up to three days (live mode).
Frappe webhook.py, v15Shopify duplicate webhooksRazorpay best practicesStripe webhooksWhat you give up, and how it fails.
What you give up
| What you get | What it costs |
|---|---|
| Misses and doubles surface within a day, not at month-end. | The job needs the scheduler running; if it is off, nothing runs. |
| People work a short exception list, not the whole ledger. | Matching rules can be wrong, and accepting weak matches hides errors. |
| It catches what retries cannot: events that never arrived. | It only finds differences against a record that exists. No statement, no check. |
How it fails
| What happens | Why | Evidence |
|---|---|---|
| The sender stops sending. | Shopify deletes an API-configured webhook subscription after eight failures in a row, and says delivery "isn't always guaranteed". Events stop until someone re-creates it. | |
| One request tries to carry the whole ledger. | ERPNext's Invoice Limit and Payment Limit default to 50, and the field says "System will fetch all the entries if limit value is zero". Large parties then time out; the background job works through queued documents instead. | |
| The job never runs, and nothing says so. | When Auto Reconcile Payments is off, or the scheduler is inactive, the trigger shows a message and does nothing. | |
| "Submitted" is read as "reconciled". | ERPNext's docs: submitting queues the process and "does not itself confirm that every entry was reconciled". Read the status and the log. | |
| It matches the books to the books. | Process Payment Reconciliation allocates payments to invoices that already exist. It does not import or match bank transactions, so a payment the bank has and the books lack is invisible to it. | |
| The list is cleared instead of worked. | Forcing or auto-accepting weak matches finishes the reconciliation and leaves the difference, disguised. (Our glossary: Bank statement.) | Follows from the design |
Each failure is Documented, with the maker's own page or code, or it Follows from the design. None is a result from a MithTech client project.
In ERPNext and Frappe.
Read from Frappe v15.123.0 and v16.52.0, ERPNext v15.122.0 and Frappe's payments app at commit 9885a6e5 on 14 October 2026, with the file and line. Other systems' names and settings were not checked here.
Where each part lives
| Feature | Where | What it does |
|---|---|---|
| Payment Reconciliation (manual) | Accounts › Payment Reconciliation | Allocates a party's unreconciled payments to its open invoices. Invoice Limit and Payment Limit default to 50; 0 fetches everything.ERPNext Payment Reconciliation, v15 |
| Process Payment Reconciliation | doctype | Queues the same allocation as a background job per party. Statuses: Queued, Running, Paused, Completed, Partially Reconciled, Failed, Cancelled.ERPNext Process Payment Reconciliation, v15 |
| Auto Reconcile Payments | Accounts Settings › Payments | Turns the queue on. The trigger runs every 15 minutes by default (1 to 59). Queue size is 5 by default (5 to 100). Jobs run on the long queue with a 3,600-second timeout. Nothing runs if the scheduler is inactive.ERPNext Accounts Settings, v15ERPNext Process Payment Reconciliation, v15 |
| Bank Transaction and Bank Reconciliation Tool | doctypes | The statement side: bank lines matched to Payment Entries and invoices. Statuses: Pending, Settled, Unreconciled, Reconciled, Cancelled.ERPNext Bank Transaction, v15 |
| Bank Statement Import | doctype | Imports a statement file as new Bank Transactions.ERPNext Bank Transaction, v15 |
| The scheduler | bench scheduler | The job only runs when it does. Our scheduler check shows how to tell. |
How to build it
Pick the outside record: the bank statement, or the gateway's settlement list. Match on its reference first.
Match in order: same reference and amount; then same amount and day with no reference (probable); then nothing (an exception).
Never post a match you cannot explain. Probable matches go to a person.
Run it on a schedule, and alert when the job has not run.
Read the exceptions weekly. A gap that repeats is a handler bug: see idempotent webhooks.