type table. The code values below are stable and safe to branch on.
Request and validation
| Code | Status | Meaning |
|---|---|---|
parameter_invalid | 400 | A field failed validation; param names it |
parameter_missing | 400 | A required field is absent; param names it |
version_required | 400 | Redbark-Version header missing |
version_invalid | 400 | The header is not YYYY-MM-DD.name, or the date predates the release |
version_unknown | 400 | The release name is not one we publish |
page_invalid | 400 | page is not a token we issued |
page_filters_changed | 400 | A filter differs from the one encoded in page |
include_invalid | 400 | An include[] value this endpoint does not offer |
idempotency_key_invalid | 400 | Idempotency-Key longer than 255 characters |
body_invalid | 400 | The request body is not valid JSON |
body_too_large | 413 | Request body over 64 KiB |
destination_incomplete | 400 | Creating a sync on a destination that has no target yet |
mapping_required | 400 | YNAB, or a Sheets per_account sync, needs account_mappings for the banking accounts |
resource_missing | 404 | No object with that id belongs to this account. Also returned when a body field references an id that does not exist (param names the field, e.g. accounts, destination, rulesets, parent) |
wrong_endpoint_for_category | 400 | The account or connection is the wrong category for this endpoint: balances and account details are banking only, transactions are banking and documents, holdings and trades are brokerage only |
not_supported | 400 | The provider does not support the operation. Account product details are available only for Australian Fiskil accounts, not Plaid or Akahu |
invalid_date_range | 400 | from is after to |
from_too_old | 400 | from is more than about 7 years ago; banking providers serve no further back |
upstream_bad_request | 400 | The banking provider rejected the request, for example dates outside a New Zealand connection’s authorised period. message includes the provider’s reason. Correct the request before retrying |
transaction_search_incomplete | 400 | A single-transaction search could not confirm absence within its 5,000-row or page budget. Narrow from/to and retry |
transaction_not_found | 404 | No matching transaction in the searched date window. Pass dates covering the transaction; the default window is the last 30 days |
account_unavailable | 404 | The provider no longer returns this account (closed, or removed from the consent). It stays in list_accounts with status: unavailable. Not retryable: skip it until available again |
route_missing | 404 | No route matches the method and path |
Authentication and permission
| Code | Status | Meaning |
|---|---|---|
api_key_missing | 401 | No Authorization header |
api_key_invalid | 401 | Unknown, revoked or expired key |
oauth_token_invalid | 401 | Invalid or expired OAuth access token, or a token not issued for this API; sign in again or obtain a new token |
insufficient_scope | 403 | The key lacks the scope the operation needs |
scope_not_held | 403 | Creating or rotating a key whose effective scopes the caller does not hold. |
ip_not_allowed | 403 | The key has an allowlist and your IP is not on it |
plan_upgrade_required | 403 | The plan has no API access |
subscription_required | 403 | Creating or reauthorizing a link session when the account has no active trial or subscription; applies to every caller |
connection_limit | 403 | Creating a link session when the plan has no free connection slot; a reauthorization is exempt |
professional_required | 403 | Brokerage data, or a brokerage link session, needs a Professional plan |
sync_limit_reached | 403 | The plan’s sync limit is used up |
Conflicts and idempotency
| Code | Status | Meaning |
|---|---|---|
idempotency_key_reused | 409 | Same key, different parameters |
idempotency_key_in_use | 409 | The first request with this key is still running |
key_limit_reached | 409 | Too many active API keys |
key_revoked | 409 | Rotating a revoked key |
key_already_rotated | 409 | Rotating a key that already has a replacement |
key_expired | 409 | Rotating a key whose expires_at has already passed |
sync_already_running | 409 | A run for the sync is queued or running |
sync_disabled | 409 | Running a disabled sync |
sync_has_no_destination | 409 | The sync has no destination to run or map against |
run_not_cancellable | 409 | Only queued runs can be cancelled |
destination_in_use | 409 | Another sync already writes to this destination, or a run is writing to it during delete |
destination_disabled | 409 | The destination is auto-disabled; enable it first |
destination_exists | 409 | A webhook destination with this URL already exists |
no_resources | 409 | Webhook destinations have no resources to list |
not_a_webhook | 409 | Rotating the secret of a non-webhook destination |
provider_mismatch | 409 | Reauthorize link session provider differs from the connection’s |
category_has_children | 409 | Deleting a group that still has categories (pass cascade=true) |
category_is_group | 409 | Groups cannot claim sources or be moved under another group |
rule_limit_reached | 409 | A ruleset holds at most 50 rules |
ruleset_duplicate_failed | 409 | The ruleset could not be duplicated; safe to retry |
event_destination_limit_reached | 409 | At most 10 event destinations |
no_subscribed_destination | 409 | Redelivering an event no enabled destination subscribes to |
*_create_failed, *_rotate_failed, ping_failed, categories_seed_failed, destination_link_complete_failed | 409 | A write did not take effect; safe to retry |
Rate limiting
| Code | Status | Meaning |
|---|---|---|
too_many_auth_attempts | 429 | Pre-authentication request limit for this IP and key prefix. Only failed authentications spend the 60/minute failure budget; a separate 600/minute ceiling counts all requests |
rate_limit_exceeded | 429 | Per-key tier limit; see Retry-After |
too_many_concurrent_requests | 429 | More than 4 heavy requests in flight on one key |
balance_refresh_limited | 429 | GET /v2/accounts/{account}/balance only: caching is disabled and the Fiskil account had a live balance attempt within 15 minutes; retry after Retry-After. Bulk balance routes return the account as unavailable with retry_after_seconds instead |
provider_wait | 429 or 503 | Shared banking admission deferred the request; 429 is a per-account cooldown, 503 is pool capacity — retry after Retry-After |
upstream_rate_limited | 429 | The banking provider itself rate-limited the request; retry after Retry-After |
Upstream and internal
| Code | Status | Meaning |
|---|---|---|
upstream_failed | 424 | The provider or destination returned a definitive error |
upstream_auth_failed | 424 | The banking provider rejected the connection’s authorisation; reconnect before retrying |
upstream_unavailable | 503 | The provider is down or the circuit breaker is open; retry after Retry-After |
gateway_unavailable | 503 | The connection gateway could not be reached; retry after Retry-After |
upstream_timeout | 503 | The read did not complete inside its request budget; retry after Retry-After |
internal_error | 500 | Our fault; quote request_id |
sync_dispatch_failed | 500 | The run row exists but could not be handed to the worker; retry the run |
connection_delete_failed | 500 | Revocation did not complete; retry |

