Credit card data moves more than checking-account data: rows are restated as a
bill closes, instalments are re-dated to the cycle they belong to, and pending
purchases are confirmed. This page explains what that does to transaction ids
and how to reconcile through it.
What identifies a transaction across syncs#
On every sync Pluggy matches the transactions it just collected against the ones it already stored, using a single key:
- The institution's own transaction id, when the connection provides one.
- Otherwise, a value derived from the transaction's
description,amount,date, and its position among identical transactions on the same day.
The consequence is the important part:
| Outcome | What you receive | Does the id survive? |
|---|---|---|
| The key matches | transactions/updated | Yes — the stored transaction is updated in place. |
| The key does not match | transactions/deleted for the old row, transactions/created for the new one | No — the transaction comes back with a new id. |
So a change in the description, amount or date of an already-stored transaction is, by construction, a different transaction. That is why a restatement around a bill closing can arrive as a delete followed by a create rather than as an update.
The ids cannot be preserved, and nothing links the old id to the new one
There is no option to keep the original id across a delete and re-create, and
the transactions/deleted payload carries only the ids that were removed — no
field points from a deleted transaction to its replacement. Any integration that
treats the Pluggy id as a permanent primary key for a credit card transaction
will drift.
What to anchor on instead#
providerId — the institution's own transaction id — is the only stable
provider-side identifier Pluggy exposes, and it is returned for Open Finance
connectors only. On a direct connector it is always null, whatever the
institution is.
This matters when the same institution is reachable both ways. Itaú, for
example, has both direct connectors and Open Finance ones: a card connected
through the direct connector never carries providerId, the same card connected
through Open Finance does.
If you have no providerId, reconcile on the transaction's attributes —
date + amount + description — as described in
Transactions, and keep your own mapping from those
attributes to your internal record rather than from the Pluggy id.
See Open Finance vs Direct: field differences for the full list of fields that only one connection type fills.
Practical handling#
- Process
transactions/deletedidempotently. A transaction can disappear in one sync and come back in a later one, so a delete is not necessarily final. - Re-fetch rather than infer. After any transaction event, read the current
state with
GET /transactionsAPI for the affected account instead of reconstructing it from the event stream. - Expect the bill window to be wide. Some institutions assign an instalment to a bill months ahead of the purchase, so a credit card transaction dated in the future is not necessarily an error.
If transactions disappear and do not come back
Whether a row stopped being returned by the institution or was dropped during the
sync is not something you can tell apart from the API response alone. Open a
support ticket with the itemId, the account, and the dates involved, and we can
check the execution — see Reporting issues.
