# Authentication

A key is a bearer credential. Send it in the `Authorization` header on every
request:

```bash
curl "https://api.fentlig.se/v1/notices?status=open" \
  -H "Authorization: Bearer fent_sk_..."
```

Keys are not accepted in a query string.

## Which plan includes what

- **The REST API** is included in the Koncern plan. A key from an account on
  another plan is refused on `/v1`.
- **The MCP server**, for AI assistants, is included in every plan. See
  [MCP server](/utvecklare/mcp). An assistant connects by signing in and
  needs no key.
- **Reading a single notice** (`GET /v1/notices/{id}` and
  `GET /v1/notices?slug=`) needs no key and no plan.

## Getting a key

An account owner creates keys in the Fentlig app under **Inställningar >
API-nycklar** (Settings > API keys). The secret is shown once, when the key is
created. If you lose it, create a new key and revoke the old one. A revoked
key keeps its usage history.

Keys belong to the account, not to the person who created them, and keep
working when that person leaves.

## Scopes

A key carries a list of scopes, each in the form `resource:action`. You
choose them from the scopes your plan includes when you create the key.

| Scope | Covers | Used by | Plans |
| --- | --- | --- | --- |
| `notices:search` | Searching and listing notices, including closed and older ones | REST: listing `/v1/notices`. MCP: `search_notices`, `find_similar_notices` | Every plan |
| `buyers:read` | Buyer records and their figures | MCP: `search_buyers` | Every plan |
| `awards:read` | Award outcomes at market level: volumes, procedures, distributions | MCP: `get_market_stats` | Every plan |
| `analysis:read` | Requirements and award criteria extracted from a procurement | REST: `evaluation_method`, `quality_weight_min`, `contract_months_min`, `contract_months_max`. MCP: `get_requirements` | Every plan |
| `documents:read` | The text of the tender documents | REST: `document_search`. MCP: `read_document`, and `document_search` on `search_notices` | Every plan |
| `competitors:read` | Named winners, supplier histories, competitors and contracts | MCP: `get_supplier_history`, `get_competitors`, `search_contracts`, `summarize_contracts` | Team and Koncern |

On the REST API, every scope also needs the Koncern plan.

To ask about a scope your plan does not include, write to
[info@fentlig.se](mailto:info@fentlig.se).

## Which endpoints need a key

Reading a single notice is open to anyone. Listing notices needs a key with
`notices:search`. Each endpoint's reference page says which applies.

Without a key, the notices are published as pages at
[fentlig.se/upphandlingar](https://fentlig.se/upphandlingar). Each page is
also available as Markdown at the same address with `.md` added, and every
page address is listed in [sitemap.xml](https://fentlig.se/sitemap.xml).

## 401 and 403

A **401** means the key is unknown, revoked or expired. The response carries
`WWW-Authenticate: Bearer`. Send a different key.

A **403** means the request is not allowed. The `code` says why:

| Code | Meaning | What to do |
| --- | --- | --- |
| `LIST_NOT_PUBLIC` | You asked for a listing without a key. | Send a key, or read the published pages. |
| `INSUFFICIENT_SCOPE` | The key is valid but lacks the scope this request needs. The scope is named in `detail` and in the `WWW-Authenticate` header. | Create a key that carries the scope. |
| `ENTITLEMENT_REQUIRED` | The account's plan does not include the REST API. | Use the [MCP server](/utvecklare/mcp), or change to the Koncern plan. |
| `ACCESS_LAPSED` | The key is valid but the account's access has ended. | An account owner renews the plan, and the same keys work again. |
| `TRIAL_NOT_INCLUDED` | The account is on a trial, and API keys are not included in a trial. | An account owner chooses a plan. |

A 429 means you sent too many requests; your key is fine. See
[Rate limits](/utvecklare/rate-limits).
