> 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/reference/error-codes.md).

# Error codes

Every error response uses the shape:

```json
{ "message": "..." }
```

The messages below are the ones your integration will encounter in practice. Group them by HTTP status when writing client-side handlers — the `message` wording may change without notice, but the status code + endpoint is stable.

For the shape and general rules, see [Error model](/guides/error-model.md).

## 400 Bad Request

| Message                                | When                                                                                   | Fix                                            |
| -------------------------------------- | -------------------------------------------------------------------------------------- | ---------------------------------------------- |
| `Idempotency-Key must be a valid UUID` | The `Idempotency-Key` header on a write request is not a UUID                          | Generate a UUID (any version — v4 is standard) |
| `Unsupported grant type`               | OAuth `POST /api/auth/oauth/token` with a `grant_type` other than `client_credentials` | Send `grant_type: "client_credentials"`        |
| *(validation-specific message)*        | A field on the request body failed schema validation                                   | Read the message, correct the field            |

## 401 Unauthorized

| Message                           | When                                                                                | Fix                                                  |
| --------------------------------- | ----------------------------------------------------------------------------------- | ---------------------------------------------------- |
| `API key is required`             | The `x-api-key` header (or `Authorization: Bearer` for OAuth) is missing            | Include the credential header                        |
| `Invalid API key`                 | The key does not match any active developer app                                     | Regenerate in the portal                             |
| `API key has expired`             | The key expired (default lifetime: 90 days)                                         | Rotate — see [Key rotation](/guides/key-rotation.md) |
| `API key has been revoked`        | The key was revoked in the portal                                                   | Generate a new key                                   |
| `Invalid client credentials`      | OAuth `client_id` / `client_secret` do not match                                    | Re-copy from the portal's Credentials page           |
| `Bearer token is required`        | An OAuth-authenticated route was called without an `Authorization: Bearer …` header | Fetch a token via `/api/auth/oauth/token`            |
| `Invalid or expired bearer token` | The JWT is malformed, unsigned, or past its 15-minute TTL                           | Request a fresh token                                |

## 403 Forbidden

| Message                                          | When                                                                                        | Fix                                                                 |
| ------------------------------------------------ | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| `Application is not active`                      | The developer app was suspended or deleted in the portal                                    | Ask the portal admin to reactivate                                  |
| `Request origin is not permitted`                | The request's source IP is not in the key's / app's CIDR allowlist                          | Update the allowlist in the portal, or route through a permitted IP |
| `Insufficient scope for this operation`          | The key is valid but the app lacks a scope the route requires                               | Extend the app's scopes in the portal (does not invalidate keys)    |
| `Browser requests are not permitted on this API` | A browser sent an `Origin` header (`/api/v1/*` is not a browser-callable API)               | Call from a server, not the browser                                 |
| `Request signature validation failed`            | The optional request-signing header (`X-Gallantree-Request-Signature`) is present but wrong | Recompute the signature per the docs or drop the header             |
| `OAuth is not configured for this application`   | The app has no OAuth client credentials issued                                              | Enable OAuth for the app in the portal                              |

## 404 Not Found

| Message                          | When                                                                                              | Fix                                           |
| -------------------------------- | ------------------------------------------------------------------------------------------------- | --------------------------------------------- |
| `Application not found`          | Portal admin API — the app id does not resolve                                                    | Check the app id                              |
| `Webhook subscription not found` | The webhook id does not resolve — either it never existed, was deleted, or belongs to another app | Verify the subscription id and its owning app |

The `404` responses on resource routes (`/api/v1/loans/{id}`, etc.) return a generic message and never distinguish "doesn't exist" from "you can't see it" — that's a privacy measure, not a bug.

## 409 Conflict

| Message                                                        | When                                                                                 | Fix                                    |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------ | -------------------------------------- |
| `A different request with this idempotency key already exists` | Same `Idempotency-Key` re-used with a different body within the 24h retention window | Use a fresh key, or send the same body |

## 422 Unprocessable Entity

Semantically-invalid write requests — the shape is fine but the meaning isn't (e.g. a currency mismatch between the loan and its capital program). The specific message varies by endpoint; see the reference for each write route.

## 429 Too Many Requests

| Message                                      | When                                        | Fix                                                             |
| -------------------------------------------- | ------------------------------------------- | --------------------------------------------------------------- |
| `Too many requests. Please try again later.` | Rate-limit quota exceeded on the app's tier | Honour `Retry-After`; see [Rate limits](/guides/rate-limits.md) |

## 500 Internal Server Error

Deliberately generic. If you see one, capture:

* The response's request id (returned in the `X-Request-Id` header when present).
* The timestamp of the request.
* The route + method.

Contact support with those three fields — the server-side log has the detail that the response deliberately omits.

## 503 Service Unavailable

| Message                                                         | When                                             | Fix                                       |
| --------------------------------------------------------------- | ------------------------------------------------ | ----------------------------------------- |
| `Service temporarily unavailable`                               | Maintenance window or upstream dependency outage | Retry with back-off; honour `Retry-After` |
| `Failed to create application` / `Failed to update application` | Rare admin-API failures on portal writes         | Retry; if persistent, contact support     |


---

# 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/reference/error-codes.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.
