Error Handling
All errors return a consistent JSON shape with an HTTP status code and a plain-language message. The message field is the primary signal — there is no machine-readable error code field beyond the HTTP status.
{
"statusCode": 400,
"message": "Cannot finalize linking for application with status: PENDING_LINKING",
"error": "Bad Request"
}Status Codes
| Status | Meaning | Common Cause | Retryable |
|---|---|---|---|
| 400 | Bad Request | Missing or invalid field, or the application is in the wrong state for that operation. | No |
| 401 | Unauthorized | Missing or invalid x-api-key header. | No |
| 403 | Forbidden | The idempotency key exists but belongs to a different account. | No |
| 404 | Not Found | The applicationId or applicantId does not exist or does not belong to your account. | No |
| 409 | Conflict | An application already exists for this idempotency key and is in a non-resumable state (LINKED, PROCESSING, COMPLETED, or FAILED). Use a new idempotency key. | No |
| 429 | Too Many Requests | /initiate is limited to 20 req/min. /analyze is limited to 30 req/min. All other endpoints share a global limit of 60 req/min per IP. | Yes |
| 500 | Internal Server Error | Unexpected server error — commonly caused by a missing Mono API key or a downstream service failure. Safe to retry with backoff. | Yes |
Per-Endpoint Error Scenarios
400 errors mean different things depending on the endpoint. The message string will always describe the exact cause.
POST /applications/initiate| 400 | Missing required field (firstName, lastName, email, amount, tenor, interestRate, or idempotencyKey) |
| 400 | Invalid field value (e.g. email is not a valid address, tenor is not a positive integer) |
| 403 | idempotencyKey already used by a different account |
| 409 | idempotencyKey matches an existing application in LINKED, PROCESSING, COMPLETED, or FAILED state |
| 500 | Mono API key not configured on your account — add it in Settings before calling this endpoint |
POST /applications/:id/link-account| 400 | Application is in a terminal state: COMPLETED, FAILED, or ABANDONED — cannot re-link |
| 404 | applicationId not found or does not belong to your account |
| 500 | Mono API key not configured |
POST /applications/:id/finalize-linking| 400 | Application is not in LINKED status — must have at least one account linked first |
| 400 | No accounts have been linked to this application yet |
| 404 | applicationId not found or does not belong to your account |
POST /applications/:id/analyze| 400 | Application has no linked bank accounts — linking must complete before analysis |
| 404 | applicationId not found or does not belong to your account |
Retry Guidance
400, 401, 403, 404 — Do not retry
These indicate a problem with your request. Fix the payload, check your API key, or verify the applicationId before trying again. Retrying without a change will return the same error.
409 — Do not retry with the same idempotency key
If the conflicting application is in PENDING_LINKING or ABANDONED state it will be automatically resumed — the 409 will not fire. A 409 means the application is past a point where resumption makes sense. Generate a new idempotency key to start fresh.
429 — Retry with exponential backoff
Wait at least one full minute before retrying. Build exponential backoff into your integration. The rate window resets every 60 seconds.
500 — Safe to retry with backoff
Most 500s are transient. Retry up to 3 times with exponential backoff (e.g. 1s, 2s, 4s). If the error persists, the most common cause is a missing Mono API key — verify it in Settings.
idempotencyKey on /initiate to safely retry on network timeouts without creating duplicate applications.