Skip to navigation

Errors

One envelope for every error, with stable machine-readable types.

Every error response (auth failures, validation rejections, rate limits, server faults) carries the same JSON envelope:

{
"error": {
"type": "not_found",
"message": "No borrower with that id exists in this workspace.",
"request_id": "req_0123456789abcdef01234567"
}
}
  • type: a stable, machine-readable identifier. Branch on this, never on message.
  • message: human-readable detail. Wording can change without notice.
  • request_id: matches the X-Request-ID response header. Include it when contacting support; it lets us find the exact request.
  • details: optional object of string values carrying the narrow, contract-level context a caller needs in order to act (for example current_version on a 409 version conflict, or the reservation figures on insufficient_credits). Absent when there is nothing actionable to add. On validation_failed it maps each offending field to its message.

Adding a new type is a non-breaking change; renaming or removing one is breaking and versioned. Treat an unrecognized type according to its HTTP status class.

Status codes

StatusMeaning
400The request is malformed or fails validation (invalid_request, validation_failed, invalid_cursor, invalid_limit, invalid_version, …)
401Missing or invalid credentials (unauthorized)
402The workspace has no active subscription or cannot fund the call (subscription_required, billing_required, spend_cap_reached, insufficient_credits)
403Authenticated but not allowed (forbidden, insufficient_scope, plan gates)
404The resource does not exist in your workspace (not_found). Also returned rather than 403 for ids you cannot see
405The path exists but does not accept the request’s method; the Allow header lists the methods it does (invalid_request)
409The write conflicts with current state (conflict, idempotency_request_mismatch, idempotency_response_too_large)
413Over a size cap: a synchronous export over its line-item cap (doc_too_large), or a request body over 16 MiB sent with an Idempotency-Key (invalid_request)
415The request body’s Content-Type is not one the operation accepts. Send a JSON body as application/json (invalid_request)
423A finalized spread or memo refuses the write until it is reopened. spread_locked from spread board writes made from the workspace or an embed session, and from PUT /api/borrowers/{borrower_id}/extractions/fin-ebitda-addbacks while a finalized spread holds the entity the add-backs belong to (any finalized spread on the loan holds the whole-loan scope); memo_locked from a render request on a finalized memo
429Rate limited or throttled (rate_limited, usage_throttled, idempotency_in_progress). Honor Retry-After. See Rate limits
5xxServer fault (internal_error). A mutation sent with an Idempotency-Key replays the fault under that key rather than re-running; see Idempotency before resending

Common error types

typeStatusWhen
unauthorized401Missing, malformed, revoked, or wrong-environment API key
forbidden403The caller’s role or session kind cannot perform this action
insufficient_scope403The API key lacks a required scope. The message names it
mode_mismatch403The key’s mode cannot call this endpoint. The sandbox reset, for example, runs on test-mode keys only
test_key_remint_required / sandbox_missing403The test key has no usable sandbox. Create a new test key in the dashboard
billing_required402The workspace has no active subscription. Set up billing, then retry
subscription_required402The workspace has no active or trialing subscription. Returned on every /api path except /api/me and the paths under /api/organizations/ and /api/sandbox/; GET /api/organizations itself is not exempt
spend_cap_reached402Upload and intake only: the workspace’s monthly usage limit is reached
insufficient_credits402Upload and intake only: prepaid credits cannot cover the reservation. details carries balance_usd, reserved_usd, in_flight_docs, incoming_docs and per_doc_reservation_usd as decimal strings
usage_throttled429Upload and intake only: the workspace is under an admission throttle. Honor Retry-After
embed_not_in_plan / counterparty_not_in_plan / spreads_not_in_plan / statement_mapping_not_in_plan403The feature is not in the workspace’s plan: embed sessions, the owners read on a borrower’s extractions, the chart of accounts and its export map, and the statement mapping reads
rate_limited429Over budget for the endpoint’s policy, or throttled. See Rate limits
invalid_request400Failed validation; message names the field
invalid_request405, 413, 415The request could not be accepted as sent; the status says why: the method, a body over the size cap sent with an Idempotency-Key, or the body’s Content-Type
validation_failed400A request field failed validation; details maps each field to its message
invalid_include400The include parameter on a loan read carries an unknown value; the message lists the supported values
invalid_request with message borrower_loan_mismatch400The upload request’s borrower_id is not the borrower of the loan named by loan_id. In the batch presign the same string is the per-file error value
spreadsheet_upload_disabled400Spreadsheet uploads are not accepted; submit the document as a PDF
invalid_cursor / cursor_expired / invalid_limit400Pagination inputs: restart iteration without a cursor
invalid_version400Unrecognized SpreadSpace-Version header value
not_found404No such resource in your workspace
not_found with message loan_not_found404The presign request named a loan that does not exist in your workspace. In the batch presign the same string is the per-file error value
conflict409Stale version or duplicate state transition; details.current_version when applicable
idempotency_in_progress429A request with the same Idempotency-Key is still executing. Retry after Retry-After
idempotency_request_mismatch409The same Idempotency-Key was reused with a different request body
idempotency_response_too_large409The original request under this key completed, but its response exceeded the 1 MiB replay cap and cannot be replayed. Read the resource instead of resending
doc_too_large413The synchronous single-document export exceeds its line-item cap; create an export instead
internal_error500Unexpected server fault. Contact support with the request_id. Under an Idempotency-Key the fault is replayed; confirm the resource state before resending with a new key

Embed sessions have their own type family. At mint time (POST /api/embed/sessions): embed_scope_exceeds_key and embed_scope_not_allowed, both 400, and embed_origin_not_allowed, 403, when the mint request carries an Origin header that is outside the key’s allowed origins. When a session token is used: invalid_embed_token, embed_token_expired and embed_session_not_found (a revoked session), all 401, and embed_session_binding_mismatch, 403, when the token reaches a loan or borrower it was not minted for. On the iframe handle exchange: invalid_session_handle, session_handle_already_used and session_handle_expired, all 401, and same_origin_required, 403. The Embed flow describes when each arises.