REST API
No web scraping
Please use the REST API for all automated access. Scraping the web interface is not supported and can fail in unexpected ways. The API offers every endpoint a programmatic integration needs.
The Librario REST API lets you integrate and automate your library processes programmatically. It exposes the functions of Librario that matter for your existing IT infrastructure and your workflows.
Two API versions
There are currently two versions of the API. They are reachable independently of one another and differ in both their data model and their sign-in.
| v3 | v2 | |
|---|---|---|
| Status | Preview | Deprecated, shutting down at the end of 2026 |
| Base URL | /api/v3 |
/api/v2 |
| Sign-in | OAuth 2.1 | Basic authentication or session cookie |
| Identifiers | typed identifiers list |
flat doi, isbn, pmid, … fields |
v3 clears out the legacy of v2: dedicated endpoints for nested resources, dedicated DELETE endpoints instead of _destroy markers, and a unified PATCH /users/:id.
The details are in the changelog entry API v3 available as a preview.
v2 shuts down at the end of 2026
Until then v2 stays available unchanged, and individual fields (import_state, the flat identifier parameters, two of the user endpoints) already carry X-API-Deprecation headers.
If you run v2 in production, plan the move to v3 now.
v3 is a preview
The interface can still change before the stable release. For production use we recommend planning the migration now and carrying it out once v3 is stable.
Reaching the API
The API is available at:
https://<your-company>.mylibrar.io/api, for example: https://app.mylibrar.io/api
If you have been assigned your own subdomain, use it in the URL.
The complete reference
The full API documentation is available in two formats:
-
Swagger UI: An interactive web interface for exploring the API
- Available at
https://<your-company>.mylibrar.io/api - Lets you call endpoints directly
- Shows example requests and responses
- Offers the OpenAPI specification as
swagger.yamlfor download
- Available at
-
OpenAPI specification (
swagger.yaml): A machine-readable description of the API- The basis for generating API clients automatically
- Can be imported into API development tools
- Useful with AI tools such as ChatGPT or Claude
Runnable examples
Ruby and Python scripts for a minimal client, availability checks against a reference-manager export and a data import with file uploads are on REST API: examples. The script for the OAuth sign-in is on the German reference.
Authentication
The two API versions sign in differently.
v3: OAuth 2.1
v3 accepts OAuth 2.1 with the authorization code flow and nothing else. There is no sign-in with a username and password. An access token is valid for one hour and comes with a refresh token that renews itself on every use.
Every token is valid for exactly one target resource, namely https://<your-company>.mylibrar.io/api/v3.
You pass that address in the resource parameter when authorising.
For a self-registered client without the parameter, the authorization server answers error=invalid_target, because a token with no fixed target resource could be replayed against a different interface.
The exception is a client registered with no scope beyond library:read and assets:read.
This includes a registration with no scope at all, which Librario stores as those two.
If such a client omits resource, Librario binds the token to the MCP server.
/api/v3 refuses that token with 401.
The WWW-Authenticate header then carries error="invalid_token" and error_description="audience mismatch".
So always send resource in scripts for the REST API.
For a client an administrator issued, Librario fills in the surface chosen at creation.
When you redeem the code, the token inherits the target resource of the authorization; if you send resource there anyway, it has to match.
One click is enough to try it out
Open https://<your-company>.mylibrar.io/api and click Authorize.
Client, PKCE, and target resource are already filled in there.
Once signed in you can call every endpoint straight from the Swagger UI.
Public and confidential clients
A client is public when it does not authenticate itself at the token endpoint, and confidential when it does, with a client secret. Librario issues both. Which one you get is decided on one of two paths.
Self-registration (Dynamic Client Registration).
Your program registers itself at POST /oauth/clients.
The token_endpoint_auth_method field decides the type: the value none yields a public client with no secret.
Leave the field out and RFC 7591’s default client_secret_basic applies, so you get a confidential client with a secret.
The supported methods are none, client_secret_basic, and client_secret_post.
The client_secret appears in the registration response and nowhere else; it is never handed out a second time.
Issued by an administrator.
If the client should belong to the account rather than to the person who registered it, an administrator issues a client for the REST API surface.
The client, with its registration, client secret, rotation and revocation, belongs to the account and stays in place when people come and go. Each connection belongs to the person who signed in and runs with their roles. When that person leaves the team, someone else signs in once and the integration carries on with the same client.
The same applies to connectors that ask for a client ID and client secret up front.
Administrators see the client in the account administration, rotate its client secret with a changeover window, and end every connection at once by revoking it.
Those clients are always confidential; they authenticate with client_secret_basic or client_secret_post.
With client_secret_basic, send the client ID and client secret as HTTP Basic authentication to POST /oauth/token; code and code_verifier go in the request body as for a public client.
The client secret is shown exactly once, and at most two are valid at a time so a rotation runs without interruption.
Creating, rotating and revoking are described on OAuth clients for integrations.
This path is part of advanced AI controls and is open only on plans that include them; self-registration is not affected.
Librario requires PKCE (method S256) from every self-registered client, public or confidential.
For a client an administrator issues, PKCE is a choice at creation and is on by default; turn it off only when the connector sends no code_challenge.
If a tool registers itself and sends no code_challenge, support can lift the requirement for the confidential clients of your account.
For public clients PKCE always stands.
v3: Permissions
A token carries the intersection of the requested permissions, what the client registered for, and what the person signing in released on the consent screen.
| Scope | Allows | Endpoints |
|---|---|---|
library:read |
Read publications, hard copies, collections, and authorities | GET /publications, /hard_copies, /authorities, /collections, /hard_copies/locations |
library:write |
Create and change library data; for publications, hard copies, and collections also delete it | POST/PATCH/DELETE /publications, /hard_copies, /collections; POST/PATCH /authorities (no delete, use merge instead); PATCH /hard_copies/locations (change and merge only, no create and no delete); GET /publications/cover/presign |
assets:read |
Read attached files and download links | GET /assets/:id; also decides whether url, thumb_url, and preview_url appear in responses from /assets and /publications at all |
assets:write |
Upload, change, and delete attached files | POST/PATCH/DELETE /assets, GET /assets/presign; also covers file content sent along in assets/assets_attributes when creating or changing a publication; library:write alone is not enough for that |
users:read |
Read the user directory | GET /users, GET /users/:id; GET /users/me returns your own record and requires no scope |
users:write |
Manage users | POST/PATCH/DELETE /users, GET /users/avatar/presign |
tasks:read |
Read tasks and quality reviews | GET /tasks |
tasks:write |
Create, edit, and complete tasks | POST/PATCH /tasks |
If a token is missing a permission, the API answers 403 InsufficientScope and names the missing scope in the WWW-Authenticate header.
Tokens issued before assets:read and assets:write existed received those permissions automatically wherever they carried library:read or library:write.
v2: Basic authentication or session cookie
v2 knows two methods:
- Basic authentication with the usual Librario credentials.
- Session cookie (
_library_session), when the call comes from a browser session that is already signed in.
In both cases the permissions match the roles configured in the application.
Technical users for integrations
We recommend setting up dedicated technical accounts for automated processes. That keeps the integration independent of personal accounts and makes access rights easier to manage.
Examples for v2 are not documented here. The complete description is in the OpenAPI specification at https://<your-company>.mylibrar.io/api/v2/swagger.yaml.
Data format
The API exchanges data as JSON, a format that every common programming language handles easily.
Pagination
List endpoints return 25 entries per page, 50 at most. To retrieve every record, request the pages one after another.
Two response headers help you navigate:
X-Total: the total number of available entriesLink: URLs for the first, previous, next, and last page
Best practices
Request rate
Please limit automated access to roughly 60 requests per minute, use pagination for list queries, and process large volumes in smaller batches.
Error handling
The API uses the following HTTP status codes:
200: request succeeded401: not authorised, for example because the token has expired403: access denied or permission missing (InsufficientScope)404: resource not found. When creating or updating a publication, also when anidfor a contributor, category or organization does not exist in your account (category and organization in API v3 only)422: input could not be processed429: too many requests500: internal server error
Error responses carry additional detail as JSON:
{
"error": {
"code": "RecordNotFound",
"message": "Requested record not found"
}
}