For the complete documentation index, see llms.txt. This page is also available as Markdown.

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

Field
Type
Present on
Description

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 means include_errors: true never 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 code for consent_errors; same native_account_id + code for account_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 own job_id/timestamp. In practice, this means an ongoing outage can show up up to 4 times in a row. Group by code (or native_account_id + code) and use the most recent timestamp as "still failing as of", rather than counting occurrences as separate incidents.

  • account_id can be null. It's resolved by looking up the bank's native_account_id against Finqware's cache of already-synced accounts. If an account has never synced successfully — Finqware has no record of it yet — account_id will be null. native_account_id is 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_errors is 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