> For the complete documentation index, see [llms.txt](https://developers.gallantreecapital.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.gallantreecapital.com/guides/error-model.md).

# Error model

Every error response has the same shape:

```json
{ "message": "Human-readable explanation." }
```

* The **HTTP status code** carries the semantics.
* The **`message`** is a short human-readable string, suitable for logs and support tickets. It is **not** meant to be parsed by clients — its wording may change without a version bump. Discriminate on status code, not on message text.
* **No internal detail leaks out.** Error responses never include stack traces, database driver names, third-party service names, or version numbers. If you need those for triage, contact support with the timestamp of the failing request — Gallantree's server-side logs have the detail.

## Status codes

### 2xx — success

| Code             | When                                                       |
| ---------------- | ---------------------------------------------------------- |
| `200 OK`         | Successful `GET`, `PUT`, or replay of an idempotent `POST` |
| `201 Created`    | Successful `POST` that created a resource                  |
| `204 No Content` | Successful `DELETE`, or a successful action with no body   |

### 4xx — you sent something the API cannot process

| Code                       | When                                                                                                                                          | Recovery                                                                           |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| `400 Bad Request`          | Validation failed — a required field is missing, a value is the wrong type, or a bound is violated                                            | Read the `message`, fix the request, resend                                        |
| `401 Unauthorized`         | No API key, invalid key, or expired key                                                                                                       | Re-check the key against the portal; regenerate if expired                         |
| `403 Forbidden`            | Key is valid but the request is not permitted — insufficient scopes, IP not in allowlist, or app suspended                                    | Fix the scope in the portal, or fix the IP allowlist                               |
| `404 Not Found`            | The resource does not exist, or you do not have access to it                                                                                  | The API does not distinguish "doesn't exist" from "you can't see it" for privacy   |
| `409 Conflict`             | An idempotency key has been used with a different payload; or a resource-state conflict (e.g. cannot delete a loan that has active drawdowns) | Read the message; either use a new idempotency key or resolve the underlying state |
| `410 Gone`                 | The resource used to exist but has been deleted                                                                                               | Do not retry — the deletion is permanent                                           |
| `413 Payload Too Large`    | Document upload exceeds the per-file limit                                                                                                    | Split the upload                                                                   |
| `422 Unprocessable Entity` | Request is well-formed but semantically invalid (e.g. a currency mismatch)                                                                    | Read the message, fix the semantics                                                |
| `429 Too Many Requests`    | Rate limit exceeded                                                                                                                           | Honour `Retry-After`; see [Rate limits](/guides/rate-limits.md)                    |

### 5xx — the API broke

| Code                        | When                                                                      | Recovery                                                                                   |
| --------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `500 Internal Server Error` | Unexpected server failure                                                 | Log the timestamp, retry with back-off; if it persists, contact support with the timestamp |
| `503 Service Unavailable`   | Upstream dependency temporarily unavailable, or the API is in maintenance | Retry with back-off; honour any `Retry-After`                                              |

## Idempotency + errors

If you retry a write request with the same `Idempotency-Key`, you'll get the **original response** — success or failure. The API does not re-attempt a failed write on replay; it returns the recorded outcome. If the original request produced a `500`, retrying with the same key returns the same `500`. Use a fresh key to actually retry the operation. See [Idempotency](/guides/idempotency.md).

## Recognising the same class of error programmatically

Because the `message` may change wording, discriminate on **status code + endpoint**:

```typescript
try {
  await client.createLoan(payload);
} catch (err) {
  if (err.status === 429) return retryWithBackoff();
  if (err.status === 401) return refreshCredentials();
  if (err.status >= 500) return retryWithBackoff();
  throw err; // 400/409/422 — fix the request
}
```

## Recognising specific errors

The full list of specific error strings — the ones you'll see in real integrations — is on [Error codes](/reference/error-codes.md). They're grouped by HTTP status and cross-referenced against the routes that produce them.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developers.gallantreecapital.com/guides/error-model.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
