Skip to main content

How do I set up Plaid /transactions/sync for bank feed reconciliation?

Call /transactions/sync with a null cursor the first time for an Item, store the next_cursor it returns, and pass that cursor back on every later call to fetch only what changed. Loop while has_more is true, and process the added, modified, and removed arrays as three distinct kinds of change — not as one undifferentiated transaction list.

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

Part of the finance integrations guide.

First callcursor: null — returns the first page of transaction history plus a cursor
Later callsPass the stored next_cursor to fetch only changes since the last sync
Pagination signalhas_more: true means more pages exist for this sync; keep calling until false
Multi-account noteEach account_id needs its own stored cursor if an Item has multiple accounts
Response shapeThree arrays per call: added, modified, removed

Why sync instead of get

Loopfour's Plaid integration is built on /transactions/sync rather than repeatedly re-fetching the full transaction history. Plaid's own documentation frames the endpoint around a cursor: leave it null for the first call on an Item, and the response returns both a page of transaction data and a cursor to pass on the next call. Every subsequent call with that cursor returns only what changed since the last one — not the whole history again — which is what makes it practical to poll on a schedule without re-processing transactions you've already reconciled.

What the cursor actually tracks, and what breaks if you get it wrong

The cursor has to be persisted per Item (and, if an Item covers multiple accounts, tracked per account_id) — it's Plaid's bookmark for exactly what state you've already seen, not a generic pagination token you can discard between calls. Lose it, and the only recovery is starting over with cursor: null, which re-returns the full transaction history as if nothing had been synced before; a reconciliation process that isn't idempotent against reprocessing old transactions will create duplicate matches when that happens.

Treat added, modified, and removed as three different jobs

Every sync response separates changes into three arrays, and each one calls for different handling: added transactions are new — reconcile them normally; modified transactions are in-place updates to something you've already seen (a merchant name correction, a category change) — update the stored record, don't create a new one; removed transactions need their existing match, if any, treated as orphaned and re-resolved (often against a new transaction that just showed up in the same call's added array with a different transaction_id, for pending-to-posted transitions). Handling all three the same way — as if every entry were a fresh transaction to reconcile — is the most common way this integration goes wrong.

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

Field mapping

What each /transactions/sync response array means for reconciliation state

ArrayWhat it meansWhat to do
addedA transaction new to this Item since the last cursorRun normal reconciliation matching
modifiedAn existing transaction_id with changed fields (name, category, amount)Update the stored record in place; don't re-match
removedA transaction_id no longer valid — often a pending transaction that posted under a new idOrphan any existing match; check this call's added array for a replacement

Frequently Asked Questions

Every call would return the full transaction history again as if nothing had changed, which both defeats the point of sync and risks re-triggering reconciliation on transactions already matched — always persist and reuse the cursor.

Usually not — modified means the same transaction_id with updated details. If the transaction_id itself changes, that's a removed-and-added pair, not a modification, and does need re-matching.

On a schedule matched to how quickly reconciliation needs to reflect new activity — Plaid also offers a webhook that notifies when new data is available, which can trigger a sync call rather than polling on a fixed interval.

Sources

Related

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 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.

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

Comparison

Plaid vs. Stripe: which side of reconciliation are you actually looking at?

Plaid is the bank side: read-only transaction data from the account the money actually lands in. Stripe is the processor side: the system that generated the payment. They aren't two views of the same event that should match directly — both reconcile against a common bank statement line, and disagreeing is normal until that line is found.

Read more