> 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/authentication.md).

# Authentication with API keys

Every request to `/api/v1/*` carries an API key in the `x-api-key` header. This guide covers what a key is, how the API validates one, and the error responses you can expect.

For OAuth 2.0 client credentials (used for server-to-server flows where an access token is preferable to a long-lived key), see [OAuth 2.0 client credentials](/guides/oauth.md).

## Request format

```http
GET /api/v1/loans HTTP/1.1
Host: developers.gallantreecapital.com
x-api-key: gt_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Accept: application/json
```

The key goes in the `x-api-key` header — never in a query string (it would leak into server access logs) and never in the request body.

## What the API validates

On every request, the auth middleware runs the following checks in order:

1. **Key present.** No `x-api-key` header → `401` with `"API key is required"`.
2. **Key matches an active app.** The key is compared against every unrevoked key on every active app. No match → `401` with `"The API key you provided is not valid."` (deliberately generic — the response never tells you whether the key existed, was expired, or belonged to another environment).
3. **Key not expired.** Keys expire after 90 days by default. An expired key → `401` with `"API key has expired"`.
4. **App still active.** Suspended or deleted apps → `403` with `"Application is not active"`.
5. **IP allowlist matches** (if configured). If the app or key has a CIDR allowlist and your source IP isn't in it → `403` with `"IP address not permitted"`.
6. **Required scopes present** (per route). If the route needs a scope your app doesn't have → `403` with `"Insufficient scopes"`.

If every check passes, the request continues to the handler.

## The `gt_` prefix

Every developer key starts with `gt_` followed by a random suffix. The first 12 characters of the key — its **prefix** — is safe to display in dashboards, logs, and error triage tools. The rest of the key is a secret and must be treated like a password.

Storage is one-way: Gallantree stores a bcrypt hash of the full key, not the key itself. If you lose a key, the portal cannot show it again — generate a new one and revoke the old.

## Scopes

Apps declare their required data as scopes, following the pattern `<resource>:<operation>`:

| Scope                   | What it allows                                 |
| ----------------------- | ---------------------------------------------- |
| `loans:read`            | List and read individual loans                 |
| `loans:write`           | Create, update, and delete loans               |
| `organisations:read`    | List and read organisations                    |
| `organisations:write`   | Create, update, and delete organisations       |
| `individuals:read`      | List and read individuals                      |
| `individuals:write`     | Create, update, and delete individuals         |
| `capital-programs:read` | List and read capital programs                 |
| `products:read`         | List and read products                         |
| `collaterals:read`      | List and read collaterals                      |
| `base-rates:read`       | List and read base rates                       |
| `webhooks:manage`       | Create, update, delete webhook subscriptions   |
| `documents:write`       | Upload documents against a loan or application |

A request that hits a route requiring a scope your app doesn't have returns `403` — regardless of whether the key itself is valid. Extending an app's scopes never invalidates its keys; it just widens what they're allowed to do.

## Runnable example

```bash
curl -sS https://developers.gallantreecapital.com/api/v1/loans \
  -H "x-api-key: $GALLANTREE_API_KEY" \
  -H "Accept: application/json"
```

For write endpoints you'll also need an `Idempotency-Key` header — see [Idempotency](/guides/idempotency.md).


---

# 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/authentication.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.
