# Authentication & permissions

## API keys

Every request must carry an API key in the `x-api-key` header:

```http
GET /api-service/leads HTTP/1.1
Host: app.banta.co.il
x-api-key: YOUR_API_KEY
```

- Keys are created in [Organization settings → Connections & technology → API Keys](https://app.banta.co.il/organization/settings?group=integrations&tab=api) and shown only once. banta stores only a hash of the key.
- Each key belongs to exactly one organization. Every call sees and changes only that organization's data; there is no way to reach another organization's data.
- You can revoke a key at any time from the same screen, effective immediately. Keys can also have an expiry date, after which they are rejected.
- Successful creates, updates and deletes are recorded in an API log: the key, the endpoint, the affected record, the status and the duration. Request and response bodies are not stored. The log isn't shown in the app yet; contact [support@banta.co.il](mailto:support@banta.co.il) for an extract.

> A key is equivalent to a password with access to customers' personal data. Use it server-side only, never commit it to code or git, and rotate it immediately if you suspect it leaked.

## Permissions

Each key has a list of permissions. Every request is checked by **resource** and **action**:

| HTTP method | Action |
|---|---|
| `GET` | `read` |
| `POST`, `PUT`, `PATCH` | `write` |
| `DELETE` | `delete` |

The resources are `leads`, `customers`, `contacts`, `mortgage-files`, `tasks` and `lists`. Every route nested under a mortgage file (`/mortgage-files/{id}/...` - borrowers, notes, charges, milestones and so on) is checked against the `mortgage-files` resource.

Permission values:

| Value | Meaning |
|---|---|
| `admin` or `*` | Full access to every resource and action |
| `leads:*` | Every action on one resource |
| `leads:read`, `leads:write`, `leads:delete` | One action on one resource |
| `read` | Read every resource |
| `write` | Create and update on every resource (**not** delete) |

The key creation screen offers four presets: **Read only** (`read`), **Read & write** (`read` + `write`, without deleting), **Full access** (`admin`) and **Custom**, where you pick resource/action pairs from a table.

Deleting always requires an explicit permission: `admin`/`*`, `resource:*` or `resource:delete`.

Customer data is protected across resources too: changing a customer's details through the borrower endpoints requires `customers:write`, and a customer's mortgage files (in `GET /customers/{id}` and `GET /customers/{id}/mortgage-files`) require `mortgage-files:read`.

Example: a website lead form needs only `leads:write`. A BI dashboard needs only `read`.

## Authentication responses

| Status | When | What to do |
|---|---|---|
| `401 Unauthorized` | The key is missing, invalid, revoked or expired | Check the header and the key. The `reason` field says why. |
| `403 Forbidden` | The key is valid but lacks permission for this action on this resource | Add the permission or create a dedicated key |
| `403 Forbidden` with `reason: subscription_inactive` | A write (`POST`, `PUT`, `PATCH`, `DELETE`) while the organization's subscription is not active. Reading still works. | Renew the subscription |
| `503 Service Unavailable` with `reason: auth_service_error` | A temporary failure in the authentication service. The key was **not** rejected. | Retry in a few seconds |

`reason` values on a 401:

| `reason` | Meaning |
|---|---|
| `missing_api_key` | The `x-api-key` header was not sent or is empty |
| `malformed_api_key` | The key contains a space or a line break (usually a copy-paste error) |
| `invalid_api_key` | The key does not exist, was revoked or has expired |

```json
{
  "reason": "invalid_api_key",
  "error": "Unauthorized",
  "status": 401
}
```

## CORS

The API returns permissive CORS headers so that the **Test Request** button in these docs works from the browser. That does **not** make it OK to call the API from client-side code in production: anyone opening the developer tools would see the key. Put a server layer (a backend, a serverless function or an automation tool) in front of the API to hold the key.

---

Part of the banta API documentation. Full index: https://docs.banta.co.il/llms.txt
