Skip to main content

What breaks when a reconciled Plaid transaction changes to modified or removed?

Plaid transaction data isn't immutable. A pending transaction can be removed from the feed entirely and replaced by a different transaction once it posts, and a bank can remove a transaction outright. If a payment was already matched to the old transaction, that match is orphaned the moment the removal comes through, and the replacement has to be found and re-matched — it doesn't update in place.

Zuny FesterBy Zuny Fester, Head of Operations and Marketing
Reviewed by Zuny Fester
Published Last reviewed Editorial policy

Part of the finance integrations guide.

SymptomA transaction that was already matched to an invoice or payout disappears from the Plaid feed
Root causePlaid's transaction model can remove a pending transaction and add a distinct posted transaction rather than updating it in place
What Plaid's own docs say"a removed transaction will no longer appear in /transactions/get"
Where this shows upThe removed array from a /transactions/sync call, keyed by transaction_id and account_id
What to check before assuming a payment vanishedThe added array from the same or a later sync call, for a new transaction covering the same amount and account

Why a matched transaction can just disappear

Loopfour's Plaid integration uses Plaid's /transactions/sync endpoint, which reports changes as three arrays: added, modified, and removed. Most changes are genuinely in-place updates — a merchant name gets cleaned up, a category gets reassigned — and land in modified. But some changes are structural: a pending transaction settling, or a bank correcting an error, can surface as the old transaction being removed and a new one being added, rather than the existing record simply updating. Plaid's documentation for the classic (pre-sync) transactions endpoint describes this pattern directly for pending-to-posted transitions: "a removed transaction will no longer appear in /transactions/get." The sync endpoint's added/modified/removed model exists specifically to let an integration react to exactly this kind of change without re-fetching the entire transaction history.

Where this hits reconciliation

If a payment reconciliation process matched an invoice or a processor payout to a transaction while it was still pending, that match is stored against a specific transaction_id. When the pending transaction is removed and a new, posted transaction is added in its place, nothing about the invoice or payout itself changed — but the transaction_id the match was keyed on no longer exists in the feed. Left alone, this looks like the payment vanished, when what actually happened is that its identifier changed underneath the match.

How to handle it

Treat every removed event as a signal to check the corresponding added array (from the same sync call or a subsequent one) for a replacement transaction on the same account, for a matching or near-matching amount, around the same date — rather than treating a removal as a payment that needs to be re-created from scratch. Re-establish the reconciliation match against the new transaction_id. This is different from a genuinely deleted transaction (the bank reversed or voided it), which won't have a corresponding entry in added — the presence or absence of a replacement is what distinguishes "this transaction changed identity" from "this transaction is actually gone."

Next step

Map the finance workflow with the most exposure and prove the automation path.

Bring the invoice, contract, payment reconciliation, or customer finance workflow you have to defend at audit. Loopfour can map the trigger, controls, integrations, and approval loop.

Book a workflow review

Worked example

A $1,240 pending charge that changes ID when it posts

A customer's card is charged $1,240 on Monday. Plaid's feed shows it as pending with transaction_id txn_pending_881, and Loopfour's cash application matches it to the customer's open invoice the same day. On Wednesday, the charge settles at the bank. The next /transactions/sync call returns txn_pending_881 in the removed array and a new transaction, txn_posted_2214, for $1,240 on the same account in the added array. Nothing about the invoice or the payment changed — but a reconciliation process that only listens for removed events and doesn't cross-check added will show the invoice as unpaid again on Wednesday, even though the money already settled. The fix is to treat the removal as a rename, not a reversal: look up txn_posted_2214 in the same sync response and re-point the existing match to it.

Frequently Asked Questions

Not necessarily — Plaid's documentation notes that pending transaction details like name, type, amount, and category can change before settlement, which can also surface as a modified event rather than a removal. Both are possible; a reconciliation process needs to handle modified events (update in place) and removed events (find the replacement) differently.

Check the added array from the same or a following sync call for a transaction on the same account with a matching or close amount and date. If nothing shows up there after a reasonable window, the transaction was likely actually removed by the institution rather than replaced.

No — /transactions/get has the same underlying remove-and-replace behavior for pending-to-posted transitions; /transactions/sync's added/modified/removed model is Plaid's own recommended way to detect and react to exactly this kind of change, not something to work around.

Sources

Related

Integration

Why don't my Stripe payouts tie to the NetSuite bank deposit?

A Stripe payout rarely equals one NetSuite deposit line: Stripe nets many charges, fees, and refunds into one transfer settled days later. Check, in order: the payout isn't unbundled into individual charges, the deposit date doesn't match the transaction date, fees are netted not booked separately, a partial capture created a variance, or the payout is still in Undeposited Funds.

Read more

Topic

Integrations

Every finance automation vendor publishes an integrations page: a grid of logos, a claim of "seamless" connectivity, and not much else. That page answers a marketing question — does this vendor touch…

Read more

Diagnostic

What breaks when Airwallex webhooks arrive out of order during payout reconciliation?

Airwallex does not guarantee webhook delivery in the order events were generated. A deposit.settled event can arrive before the deposit.pending event that should precede it, so reconciliation logic that assumes sequential arrival can build a match against incomplete state. Order by each event's created_at timestamp and deduplicate by its id, not by arrival order.

Read more

Diagnostic

What breaks when a Xero bank transaction doesn't match the bank statement line?

A BankTransaction created through Xero's API isn't automatically linked to the real bank statement line Xero later imports. Xero's schema tracks this with an IsReconciled flag; its auto-matching compares amount, date, and contact against imported lines, and if those don't line up closely enough, the created transaction and the real line both sit unreconciled instead of resolving into one record.

Read more