Sync errors
Return the errors from the latest bank synchronisations alongside accounts, balances or transactions data.
Overview
/v1/accounts/get, /v1/balances/get and /v1/transactions/get can optionally return the errors from the client's most recent bank synchronisations alongside the normal data.
This solves a real integration problem: without it, an empty or stale-looking result is ambiguous — is there genuinely no data, or did the last sync to the bank fail? Today, answering that means reaching out to Finqware support or waiting for a webhook. With include_errors, the answer comes back on the same call, for free.
The feature is opt-in and fully backward compatible. If you omit the flag, or send it as false, the response is byte-for-byte what it is today — a plain array. Nothing changes unless you ask for it.
Enabling it
Add "include_errors": true to the request body of any of the three endpoints:
// POST /v1/accounts/get
{
"client_id": "{{client_id}}",
"client_secret": "{{client_secret}}",
"credentials_id": "{{credentials_id}}",
"access_token": "{{access_token}}",
"include_errors": true
}The flag works identically on /v1/balances/get and /v1/transactions/get, alongside whatever other parameters those endpoints already accept (filter, batch, etc.) — include_errors doesn't interact with or change any of that.
Response shape
With the flag on, the response becomes an envelope with three top-level keys instead of a bare array:
Only the name of the data key changes per endpoint — accounts, balances or transactions — the rest of the envelope (account_errors, consent_errors) is identical in shape across all three. The data array itself is never altered by this feature: same items, same fields, as when the flag is off.
Two kinds of errors
consent_errors
account_errors
What failed
The whole bank connection — e.g. the consent was revoked, credentials expired, or the bank rejected the request outright. Not specific to any one account.
One specific account failed for that endpoint's own operation. Other accounts on the same connection may have synced fine.
Appears on
All 3 endpoints — even an endpoint whose own operation never got a chance to run (see note below).
Only the matching endpoint — a balances failure only on /balances/get, a transactions failure only on /transactions/get. On /accounts/get, only for the subset of banks that fetch accounts one at a time (see note below); for the rest it's always empty there.
Identifies
Nothing account-specific — the failure applies to the whole connection.
account_id + native_account_id (the affected account).
Why a consent error can show up on /balances/get or /transactions/get even though balances/transactions were never attempted: listing accounts is always the first step of a sync. If that step fails, nothing downstream can run either — so the failure is still relevant to every endpoint, not just /accounts/get. Treat any entry in consent_errors as "this connection is down", regardless of which endpoint you called it from.
Note on /accounts/get specifically: most banks refresh all accounts in a single call, so a failure there is genuinely whole-connection and always classified as consent_errors — account_errors stays empty on /accounts/get for those. A smaller set of banks instead refresh accounts one at a time (one call per already-known account); for those, a single account's failure populates account_errors on /accounts/get just like it does on the other two endpoints, while the other accounts' data still comes through normally. Either way, treat account_errors and consent_errors as mutually exclusive for a given failure — you don't need to know which fetching style a particular bank uses to consume the response correctly.
Error object reference
code
string
both
Machine-readable identifier for the specific failure (e.g. external_api_unauthorized, external_api_forbidden, external_api_connection_error, external_api_timeout, external_api_deadline_exceeded, external_api_server_error, external_api_unavailable, external_api_unknown_error). This set is not fixed — new codes are added as new failure modes are handled. Use it for logging/support, not as an exhaustive switch.
type
string
both
Broad error category. In this context it's always external_api_error — these errors all originate from a call to the bank's own API failing.
http
integer
both
The HTTP status returned by (or attributed to) the failed bank call — not just 4xx/5xx from the bank itself, but also locally-attributed statuses for connectivity issues: 408 if the call to the bank timed out, 504 if a deadline was exceeded. A timeout is reported exactly like any other failure — same envelope, same fields, no special case. Useful for coarse-grained routing (e.g. 401/403 → prompt the user to reconnect their bank; 408/5xx → transient, safe to just keep retrying/polling).
message
string
both
Human-readable description, safe to display or log as-is.
job_id
UUID
both
The sync job this error was reported by.
timestamp
ISO 8601
both
When that sync job completed.
account_id
UUID or null
account_errors only
Finqware's internal identifier for the account. Can be null — see below.
native_account_id
string
account_errors only
The bank's own identifier for the account (e.g. IBAN or bank account number). Always present.
Where the data comes from, and how long it lasts
No live bank call is made to answer this. The errors are read straight out of Finqware's own sync history for this
credentials_id— specifically, the report each background sync job writes when it finishes. That keeps the response fast and meansinclude_errors: truenever adds latency or an extra bank round-trip.We look at the most recent 4 finished jobs, within the last 2 days.
Jobs older than 2 days are pruned automatically by a maintenance task that runs every 10 minutes. There's no separate "error state" tracked anywhere: the moment a sync succeeds, the earlier failure simply ages out of the window and stops appearing on its own — nothing to acknowledge or clear.
What implementers need to know
The same error can appear more than once — once per affected sync. Within a single job, duplicate errors are already collapsed (same
codeforconsent_errors; samenative_account_id+codeforaccount_errors). But that dedup does not carry across jobs: if a problem is still unresolved on the next sync, you'll see it again, with its ownjob_id/timestamp. In practice, this means an ongoing outage can show up up to 4 times in a row. Group bycode(ornative_account_id+code) and use the most recenttimestampas "still failing as of", rather than counting occurrences as separate incidents.account_idcan benull. It's resolved by looking up the bank'snative_account_idagainst Finqware's cache of already-synced accounts. If an account has never synced successfully — Finqware has no record of it yet —account_idwill benull.native_account_idis always present and is the reliable key for matching an error back to a specific bank account, including ones you haven't seen in your data yet.account_errorsis reported once per affected account, not repeated on every balance or transaction row belonging to that account.
Backward compatibility
include_errors is entirely opt-in. Existing integrations that don't send the flag see no change: the response stays the plain array it is today, with no new fields anywhere in it.
Last updated