# Get started

Last updated 10 September 2026
Source: https://plas.redia.dk/en/get-started/

What you need before the first call to a library system that implements the PLAS Provider API — and where the reference takes over.

The PLAS Provider API is the interface a library system exposes so that library products can read and write patrons, loans, reservations and holdings without knowing the system behind it. The party implementing the interface is the *provider*; the party calling it is the *client*. This page is written for the client — the last section for the provider.

It describes **Provider API v0.6.5**, the version *PLAS Status* lists as in production. v0.6.6 is in specification. The spec says of itself that it is still a work in progress and that fields and structure may change.

## Contents

- [Prerequisites](#prerequisites)
- [Base URL](#base-url)
- [Authentication](#authentication)
- [First call](#first-call)
- [Rules that apply to every call](#rules-that-apply-to-every-call)
- [Errors](#errors)
- [Implementing the API yourself?](#implementing-the-api-yourself)
- [Next steps](#next-steps)

## Prerequisites

- A library system that implements Provider API v0.6.5.
- The system's **base URL** and a set of **client credentials** (`client_id` and `client_secret`). Both come from the provider — it decides who may call.
- A tool that can send HTTP requests and read JSON.

## Base URL

The spec has no `servers` block. The base URL belongs to the provider, not to PLAS, and is agreed with the provider. Every path in the reference — `/version`, `/patron/{patronId}`, `/authentication/oauth2/token` — is relative to it.

The spec describes two ways a provider can tell its callers apart: a **base URL per library** (so the same product calls different addresses at different libraries) or **one base URL for all**, with credentials identifying both library and vendor. Don't assume the base URL is the same from one library to the next, even with the same provider.

## Authentication

The Provider API uses OAuth 2.0 with *client credentials*. One call returns a token; the token goes on every other call.

**Get a token.** Send a `POST` to `/authentication/oauth2/token` with `Content-Type: application/x-www-form-urlencoded` and three fields: `client_id`, `client_secret` and `grant_type` with the value `client_credentials`. The call itself needs no token.

```http
POST /authentication/oauth2/token
Content-Type: application/x-www-form-urlencoded

client_id=<client_id>&client_secret=<client_secret>&grant_type=client_credentials
```

The response is JSON with three fields — all required:

- `access_token` — the token itself. The spec recommends that the provider issues a JWT, so a third party (a search API, say) can validate it without asking the provider.
- `token_type` — always `Bearer`.
- `expires_in` — the token's lifetime in seconds.

**Use the token.** Put it in the `Authorization` header on every call: `Authorization: Bearer <access_token>`.

**When it expires.** HTTP `401` means the token is missing, invalid or expired. Get a new one and retry. The schemas are in the reference: [AuthenticationClientCredentialsRequestBody](/en/provider/v0.6.5/schemas/#AuthenticationClientCredentialsRequestBody) and [AuthenticationClientResponseBody](/en/provider/v0.6.5/schemas/#AuthenticationClientResponseBody); the operation is [AuthenticateClient](/en/provider/v0.6.5/authentication/#AuthenticateClient).

## First call

Start with `GET /version`. It is the one call that needs no token, and the response tells you which API version the provider recommends — so you know the base URL is right, and which version to ask for, before you authenticate.

The response has one field, `version`. The operation is [GetVersion](/en/provider/v0.6.5/version/#GetVersion).

Then get a token and call the first operation in the group your product needs — [Patron](/en/provider/v0.6.5/patron/) for patron data, say, or [Holding](/en/provider/v0.6.5/holding/) for holdings. Each group has its own page in the reference with parameters, request body and responses per operation.

## Rules that apply to every call

These rules are stated once in the spec and apply everywhere. The shared contract — the parameters and error responses nearly every operation shares — is on the [version overview](/en/provider/v0.6.5/).

- **`version`** (query, optional) — the API version the client expects. If the provider doesn't support it, it responds with error code `600`. Send it; a version mismatch then shows up as an error rather than as a wrong field.
- **`ui_language`** (query, optional) — the language the provider returns text in. Codes follow the [MARC language list](https://www.loc.gov/marc/languages/).
- **URL and query parameters** must be URL-encoded. An id containing a comma in a comma-separated list is therefore encoded as `%2C`.
- **Dates and times** follow RFC 3339. A point in time is a `date-time` with a capital `T` and an explicit time zone — the spec assumes none. A plain date is `YYYY-MM-DD`.
- **Responses contain no HTML** unless the operation explicitly says so.
- **Lookups on a list of ids** return only the ids the provider knows. Unknown ids are left out; if all are unknown, the response is an empty map.

## Errors

An error response has two fields, `code` and `info` ([Error](/en/provider/v0.6.5/schemas/#Error)). The code is a number, and the full list is in the [ErrorCode](/en/provider/v0.6.5/schemas/#ErrorCode) schema. The three you meet first:

- `500` — system error at the provider.
- `600` — the version you asked for isn't supported.
- `10001` — the operation is disabled at this provider.

The rest are domain-specific — `100023` for an unknown `patronId`, `102001` for an unknown loan — and are listed on the operation they belong to. The HTTP codes `400`, `401` and `404` are shared responses, described on the [version overview](/en/provider/v0.6.5/).

## Implementing the API yourself?

Then you are the provider, and the spec makes three recommendations beyond the operations themselves:

- **Use a UUID as `patronId`.** If the system uses integer patron ids, add a UUID alongside and use only that in PLAS.
- **Protect patron login against brute force.** `POST /patron/authentication` and `POST /patron/authentication/no-password` need rate limiting per patron identifier.
- **Decide how you tell your callers apart** — a base URL per library, credentials per vendor, or both. The token endpoint `/authentication/oauth2/token` is yours to implement.

## Next steps

- [Version overview](/en/provider/v0.6.5/) — the shared contract and all 21 groups.
- [Schema index](/en/provider/v0.6.5/schemas/) — all 379 schemas, one level deep.
- [API reference](/en/apis/) — the four APIs, and how they fit together.
