current_balance (and an available_balance for MX accounts), plus its transactions through GET /accounts/{id}/transactions. This guide explains how fresh that data is, how to tell, and how to pull fresher data on demand.
How fresh is GET /accounts?
The balances you read are a cached snapshot from the last successful refresh — not a live call to the bank on every request. LedgerSync refreshes every active connection automatically about once a day, so under normal conditions the numbers are less than 24 hours old.
Every Account carries a last_refreshed_at timestamp — the moment its data was last refreshed. Read it to decide whether you already have fresh-enough data or need to force a refresh.
For most use cases you do not need to call
/refresh. The daily auto-refresh keeps active connections current, and GET /accounts always returns the latest snapshot. Reach for /refresh only when you need fresher-than-daily data.Forcing a refresh
When you need up-to-the-moment data (a user tapped “refresh”, you’re reconciling something time-sensitive), callPOST /connections/{id}/refresh:
202 Accepted with an operation_id and starts the refresh asynchronously, so balances are not updated by the time the call returns. All three connectable sources (Finicity, MX, and FDE) answer this call the same way: 202 now, the outcome later on a webhook.
1
POST /connections/{id}/refresh
You get
202 and an operation_id.2
Wait for the account.refresh.completed webhook
It fires when the fresh data is in (or
account.refresh.failed on a terminal failure). Listen for the webhook — don’t poll GET /accounts in a loop.3
Re-read GET /accounts (and /transactions)
The snapshot now reflects the fresh pull and
last_refreshed_at has advanced.account.refresh.completed / account.refresh.failed payload shapes, and the Refresh a connection endpoint in the API Reference for the full contract.
MX aggregates on its own schedule, several times a day, and refreshes through this same async webhook flow. A refresh you request triggers an MX aggregation, and the result arrives on the
account.refresh.completed webhook, so the shape of the call matches Finicity and FDE.What is not the same is what comes back. An MX aggregation re-reads the member’s full account list, so it also picks up accounts the client opened after linking. FDE does the same on its extraction run. A Finicity refresh does not, and no amount of refreshing will surface an account the client never shared. See Adding a new account.Refreshing many connections at once
You can refresh all of a customer’s banks in one batch — each connection is a separatePOST /connections/{id}/refresh call. That’s well within the rate limits (live keys allow 60 requests/minute), and there is no separate concurrency cap on refresh: the limit that applies is the normal request rate.
- Fire the batch, then wait on the
account.refresh.completedwebhooks — don’t poll operations or/accountsin a tight loop. - Watch the
X-RateLimit-*headers and back off before you hit zero — see Rate limits. - Each refresh triggers a real aggregation at the bank, so space large batches out rather than firing hundreds at once.
