code field, not the human-readable message.
Error envelope
Any non-2xx response has the following body:code. The message is a
human-readable string scoped to the partner contract — internal LMS
vocabulary (Client, globalisation codes like error.msg.*) is rewritten
or stripped before it reaches the wire, and it may change, so don’t parse
it. code is an error-only field: successful responses return the
resource object (no code), and 204 No Content has no body.
Some errors also carry an optional sub_code — a stable, finer-grained
business reason within a code. It lets you map an error to a specific
customer-facing message without parsing message (see
Sub-codes below). sub_code is additive and optional: an
error may omit it, and new sub-codes may be introduced over time — so always
branch on code first, and treat an unknown or absent sub_code by
falling back to the code.
For validation failures (invalid_argument), the message is a
JSON-encoded array of {field, error} pairs:
Error codes
These are the codes the API currently returns. Branch oncode.
Reserved codes (not currently emitted)
The error vocabulary also defines the canonical codes below, which the API does not currently return. They’re documented so your handler recognises them if a future version starts using one — you don’t need to handle them today. Yourcode fallback (treat any unrecognised code as a non-retryable
error and surface it) covers them safely.
Sub-codes
When present,sub_code pins down the exact business scenario behind the
code. Each maps cleanly to a fixed customer-facing message — only
validation_error requires reading message (for the per-field detail).
Branch on code first; use sub_code to refine the message you show.
Idempotency (repayments)
Repayments accept an optionalidempotencyKey (your wallet transaction
reference). Re-sending the same key on the same loan returns the
original transaction with 200 — a safe replay, not an error.
Re-using a key already recorded elsewhere (a different loan, or a race)
returns already_exists (409).
Retrying
The reserved codes aren’t returned
today; if one is introduced later,
too_many_requests / resource_exhausted
and deadline_exceeded would be retryable with backoff.

