Errors
HTTP status codes, the error response shape, and how to handle each.
Errors
These rules apply to every Financy endpoint — payments, connections,
accounts, transactions, providers, and merchants alike. Every failed request
returns a standard HTTP status code and a JSON body in this shape:
{
"type": "CLIENT_ERROR",
"message": "Payment ID is not valid"
}| Field | Description |
|---|---|
type | The error category — see Error types below. |
message | A human-readable explanation. For validation errors it may be a stringified list, e.g. "[\"clientSecret is required\"]". |
Don't confuse these with payment statuses. An HTTP error means therequest failed. A payment that is rejected by the bank still returns
HTTP 200 with a paymentstatusofRJCT— see Payment Status.
HTTP status codes
| Code | Meaning | What to do |
|---|---|---|
400 | Bad request — validation or business-rule failure | Fix the request (see examples below). |
401 | Unauthorized — missing/invalid/expired token | Get a new token and retry (see Authentication). |
402 | Payment required — not enough credits | Top up or wait for the weekly allowance; do not retry unchanged. |
403 | Forbidden — plan, scope, or account-limit | Read type in the body (see below). Don't retry unchanged. |
404 | Not found — route or entity doesn't exist | Check the id / path. |
409 | Conflict — no refreshable connection | Reconnect a bank, then retry. |
423 | Locked — the resource can't be changed yet | Wait and retry (see below). |
500 | Internal server error | Retry with backoff; if it persists, contact us. |
503 | Temporarily unavailable | Retry shortly (connector verification, upstream). |
400 — Bad request
The most common failure. type is usually CLIENT_ERROR or VALIDATION_ERROR
(and PROVIDER_UNAVAILABLE when a bank is temporarily down). Representative
messages:
{ "type": "CLIENT_ERROR", "message": "[\"paymentInformation is required\"]" }
{ "type": "VALIDATION_ERROR","message": "Merchant Id or creditor info is required" }
{ "type": "CLIENT_ERROR", "message": "Redirect url is not in allowed url list" }
{ "type": "CLIENT_ERROR", "message": "Creditor and debtor accounts are the same" }
{ "type": "CLIENT_ERROR", "message": "Payment ID is not valid" }
{ "type": "CLIENT_ERROR", "message": "Invalid provider" }
{ "type": "PROVIDER_UNAVAILABLE", "message": "The required provider is unavailable at this moment, Please contact us for more info" }
{ "type": "CLIENT_ERROR", "message": "Production access is not enabled for this organization, you must include fake providers or contact us" }
That last one is the sandbox gate: until production access is enabled,payments must target sandbox providers. Use sandbox providers to test, and
contact us to enable production.
401 — Unauthorized
{ "message": "Unauthorized" }The access token is missing, malformed, or expired. Request a fresh token from
POST /oauth/token (see Authentication) and retry. Tokens are per user, so
make sure you're sending the token for the right userId.
402 — Payment required
Returned by on-demand refresh when the org does not have 20 credits left:
{ "status": "insufficient_credits", "cost": 20, "message": "Insufficient credits for an initiated refresh" }The weekly credit balance is in the Financy app. Retrying without more credits
will keep returning 402.
403 — Forbidden
The token is valid but the call is not allowed. Unlike a missing-scope rejection
from the gateway (which may have an empty body), Financy policy rejections
include { type, message }:
{ "type": "NOT_AVAILABLE_ON_PLAN", "message": "The Financy API is available on paid plans only" }
{ "type": "ACCOUNT_LIMIT_REACHED", "message": "You've reached your plan's corporate-account limit. Upgrade, add a slot, or remove a corporate account to continue." }
{ "type": "MCP_FORBIDDEN", "message": "This connector token is missing the mcp:read scope. Reconnect the Financy connector to grant it." }
{ "type": "MCP_NO_FINANCY_ORG", "message": "No Financy account is linked to this user. Sign up at Financy first, then reconnect." }type | Meaning |
|---|---|
NOT_AVAILABLE_ON_PLAN | Free-plan API key, or a connector on a free plan. Upgrade to Starter or Pro. |
ACCOUNT_LIMIT_REACHED | This API key's org is over its corporate-account cap. Trim accounts in the app, add a slot, or upgrade — then retry. |
MCP_FORBIDDEN | Connector token is missing mcp:read. Reconnect the Financy connector. |
MCP_NO_FINANCY_ORG | The connector user has no Financy account, or their org is not a Financy org. |
Don't retry these unchanged. Missing OAuth scopes (the gateway's own 403) still
mean the key cannot do this action.
404 — Not found
The route or the referenced entity doesn't exist. type is CLIENT_ERROR:
{ "type": "CLIENT_ERROR", "message": "Payment not found with this id" }
{ "type": "CLIENT_ERROR", "message": "Merchant not found in db" }
{ "type": "CLIENT_ERROR", "message": "Provider is not allowed for this payment" }409 — Conflict
Returned by on-demand refresh when the user has no connection that can still
fetch (none linked, or all expired / revoked / otherwise dead):
{ "status": "no_refreshable_connections", "message": "No refreshable connections — reconnect a bank first" }Reconnect a bank in the Financy UI, then retry. A refresh that is already
running is not a 409 — it returns 200 with status: "already_running" and
is not charged again.
423 — Locked
Returned when deleting a Connection that can't be removed yet:
This connection is locked and can't be deleted currently. If you have BigQuery
enabled, you can only delete connections that were created at least 90 minutes ago.
Wait until the lock clears (at least 90 minutes after creation) and retry.
500 — Internal server error
Something failed on our side or at the provider. type is typically
INTERNAL_ERROR:
{ "type": "INTERNAL_ERROR", "message": "An unexpected server error has occurred" }
{ "type": "INTERNAL_ERROR", "message": "PROVIDER_ERROR" }Retry with exponential backoff. If it keeps happening, contact us with the
message and the time of the request.
503 — Temporarily unavailable
The Financy connector could not verify the caller's org right now:
{ "type": "MCP_TEMPORARILY_UNAVAILABLE", "message": "Financy could not verify connector access right now. Please try again shortly." }Retry shortly. This is not a plan or scope problem.
Error types
The type field takes one of:
type | Meaning |
|---|---|
CLIENT_ERROR | Something about the request was wrong (bad id, bad input). |
VALIDATION_ERROR | A required field was missing or invalid. |
PROVIDER_UNAVAILABLE | The target bank is temporarily unavailable. |
NOT_AVAILABLE_ON_PLAN | Free plan, or an endpoint this key cannot use. |
ACCOUNT_LIMIT_REACHED | Org is over its corporate-account cap. |
MCP_FORBIDDEN / MCP_NO_FINANCY_ORG / MCP_TEMPORARILY_UNAVAILABLE | Connector-token policy. |
INTERNAL_ERROR / INTERNAL_SERVER_ERROR | An unexpected server-side failure. |
Handling checklist
- 401 → refresh the token, retry once. If you just rotated the secret, the
old secret and any unpurged tokens are the cause — see Authentication. - 403 → read
type; don't retry unchanged. Free plan → upgrade; account
cap → trim/upgrade; connector → reconnect or sign up. - 402 → not enough credits for on-demand refresh; don't retry unchanged.
- 400 / 404 → fix the request; retrying unchanged won't help.
- 409 → reconnect a bank, then retry the refresh.
- 423 → wait, then retry.
- 500 /
PROVIDER_UNAVAILABLE/503→ retry with backoff; escalate if persistent. - A 2xx with a failed payment
status(RJCT/CANC/ERROR) is a
payment outcome, not a transport error — handle it per Payment Status.
Updated 16 days ago

