Reference
Errors
Finora Business uses a consistent response envelope. When something goes wrong, you get an HTTP status, a stable error code, a human message, and a request ID you can quote in support tickets.
The response envelope
Every response — successful or not — follows the same shape. Success responses include a data object:
{
"success": true,
"data": { ... },
"meta": {
"requestId": "req_a1b2c3d4e5f6g7h8",
"timestamp": "2026-04-17T10:30:00.000Z",
"rateLimit": {
"limit": 60,
"remaining": 58,
"reset": "2026-04-17T10:31:00.000Z"
}
}
}Error responses include an error object instead:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Request body validation failed",
"details": [
{ "field": "lineItems[0].unitPrice", "message": "must be a positive number" },
{ "field": "dueDate", "message": "must be after invoiceDate" }
],
"requestId": "req_a1b2c3d4e5f6g7h8"
}
}Always show the requestId to your users (or log it). It's how we trace requests through our logs when you file a support ticket.
General error codes
| HTTP | Code | Meaning |
|---|---|---|
| 400 | INVALID_REQUEST | Missing or invalid request parameters. |
| 400 | MISSING_BUSINESS_ID | businessId query parameter was not provided. |
| 400 | INVALID_VERSION | API version not supported. Use /v1/. |
| 400 | VALIDATION_ERROR | Request body fails schema validation. Details array lists each failed field. |
| 400 | UNBALANCED_JOURNAL | Journal entry debits do not equal credits. |
| 401 | UNAUTHORIZED | Missing or malformed Authorization header. |
| 401 | INVALID_API_KEY | API key is invalid, revoked, or expired (90-day rotation). |
| 403 | FORBIDDEN | Authenticated but no access to the requested business. |
| 403 | BUSINESS_SUSPENDED | Business subscription expired or suspended. |
| 404 | NOT_FOUND | Resource not found. |
| 405 | METHOD_NOT_ALLOWED | HTTP method not supported for this endpoint. |
| 409 | CONFLICT | Resource already exists or state conflict (e.g. voiding an already-voided invoice). |
| 422 | BUSINESS_LOGIC_ERROR | Valid request but violates a business rule. |
| 429 | RATE_LIMIT | Rate limit exceeded. See the retryAfter hint. |
| 500 | INTERNAL_ERROR | Server error. Details are logged; the response carries a requestId. |
Billing & access error codes
These are specific to the Finora Business credit-and-trial model. See Billing & credits for the pricing context behind them.
| HTTP | Code | Meaning |
|---|---|---|
| 402 | TRIAL_EXHAUSTED | You used all 100 trial calls. Top up credits to continue, or use a test_sk_ key for free sandbox calls. |
| 402 | INSUFFICIENT_CREDITS | Your credit balance is zero. Top up in the dashboard. |
| 403 | NO_SUBSCRIPTION | API keys require a Premium or Accountant Pro subscription. |
| 403 | FREE_TIER | Subscription was downgraded after the key was issued. |
| 403 | ENTERPRISE_ONLY | Endpoint is gated to enterprise accounts. Contact sales to upgrade. |
Handling errors well
Branch on the code, not the message
The message is for humans and may change. The code is machine-stable.
Respect
retryAfterOn
429 RATE_LIMIT, the error payload includes aretryAfterhint (seconds). Back off for at least that long.Don't retry 4xx blindly
Most 4xx codes indicate a problem with the request itself — fixing the input, not retrying, is the answer.
500 INTERNAL_ERRORand429 RATE_LIMITare the two worth retrying.Surface billing errors to the operator
Integrations that hit
INSUFFICIENT_CREDITSorTRIAL_EXHAUSTEDwill stop working until credits are topped up. Alert the person who owns the Finora Business account, not just the log.