Browse the docs

API reference

Auth

Sessions, tokens, profiles, two-factor and password reset. docs/11 §1.

Paths are relative to /api/v1 on your server.

GET/auth/2fa#

Read two-factor status

Authorisation
Bearer token or API key · Session cookie
  • 200Success. application/json · TwoFactorStatus
  • 401UNAUTHENTICATED: no session, or the access token expired. application/json · ErrorEnvelope
  • 403FORBIDDEN: the account may not do this. application/json · ErrorEnvelope
POST/auth/2fa/disable#

Turn two-factor off

Authorisation
Bearer token or API key · Session cookie
Body
application/json · object
  • 204Done; no body.
  • 400VALIDATION_FAILED: the request did not match the schema; details.issues lists what. application/json · ErrorEnvelope
  • 401UNAUTHENTICATED: no session, or the access token expired. application/json · ErrorEnvelope
  • 403FORBIDDEN: the account may not do this. application/json · ErrorEnvelope
POST/auth/2fa/enable#

Confirm enrolment and receive recovery codes

Authorisation
Bearer token or API key · Session cookie
Body
application/json · object
  • 200Success. application/json · RecoveryCodes
  • 400VALIDATION_FAILED: the request did not match the schema; details.issues lists what. application/json · ErrorEnvelope
  • 401UNAUTHENTICATED: no session, or the access token expired. application/json · ErrorEnvelope
  • 403FORBIDDEN: the account may not do this. application/json · ErrorEnvelope
POST/auth/2fa/recovery-codes#

Issue fresh recovery codes

Authorisation
Bearer token or API key · Session cookie
  • 200Success. application/json · RecoveryCodes
  • 401UNAUTHENTICATED: no session, or the access token expired. application/json · ErrorEnvelope
  • 403FORBIDDEN: the account may not do this. application/json · ErrorEnvelope
POST/auth/2fa/setup#

Begin two-factor enrolment

Authorisation
Bearer token or API key · Session cookie
  • 200Success. application/json · object
  • 401UNAUTHENTICATED: no session, or the access token expired. application/json · ErrorEnvelope
  • 403FORBIDDEN: the account may not do this. application/json · ErrorEnvelope
POST/auth/2fa/verify#

Finish a two-factor sign-in

Authorisation
None
Body
application/json · object
  • 200Success. application/json · SignInAnswer
  • 400VALIDATION_FAILED: the request did not match the schema; details.issues lists what. application/json · ErrorEnvelope
  • 401AUTH_2FA_INVALID: the code or recovery code is wrong application/json · ErrorEnvelope
POST/auth/forgot#

Email a reset link to an account

"Forgot password?": a single-use link, good for an hour, to the email of the account the login (a username or an email) names. The same empty answer whether or not there is such an account, or it has an email; the email goes after the answer. Only when the server sends email and its admins allow it (features.resetByEmail in GET /server/info). Ten asks an hour from an address, three links an hour for an account.

Authorisation
None
Body
application/json · object
  • 204Done; no body.
  • 400VALIDATION_FAILED: the request did not match the schema; details.issues lists what. application/json · ErrorEnvelope
  • 404NOT_FOUND: the server does not email reset links application/json · ErrorEnvelope
  • 429RATE_LIMITED: more than ten asks in an hour from one address application/json · ErrorEnvelope
DELETE/auth/identity-links/{id}#

Unlink an outside identity from its account

Its next sign-in finds the account by its email again, as a first one does: linked by itself when whoever runs the server gave the account that email, else once the account’s own password is typed. The owner’s, the owner alone.

Authorisation
Bearer token or API key · Session cookie
ParameterInTypeDescription
id requiredpathstring (uuid)
  • 204Done; no body.
  • 401UNAUTHENTICATED: no session, or the access token expired. application/json · ErrorEnvelope
  • 403FORBIDDEN: the account lacks user:manage, or the library, label, age or schedule scope refuses it. FORBIDDEN: the owner’s, and you are not the owner application/json · ErrorEnvelope
  • 404NOT_FOUND: no such thing, or not one the caller may see. NOT_FOUND: no such linked identity application/json · ErrorEnvelope
GET/auth/ldap#

Read the directory sign-in settings

Everything but the search account’s password, of which only whether one is kept.

Authorisation
Bearer token or API key · Session cookie
  • 200Success. application/json · object
  • 401UNAUTHENTICATED: no session, or the access token expired. application/json · ErrorEnvelope
  • 403FORBIDDEN: the account lacks settings:manage, or the library, label, age or schedule scope refuses it. application/json · ErrorEnvelope
PUT/auth/ldap#

Change the directory sign-in settings

Only what the body names changes. A bindPassword replaces the kept one (sealed at rest, never sent back); null forgets it. The kept one goes only to the addresses, account and certificate settings it was saved with: a change to any of them without a new bindPassword is refused. Switched on, the settings must name an address, a search base and, with a search account, its password.

Authorisation
Bearer token or API key · Session cookie
Body
application/json · object
  • 200Success. application/json · object
  • 400VALIDATION_FAILED: the request did not match the schema; details.issues lists what. VALIDATION_FAILED: a setting is not valid, or one that is needed is missing application/json · ErrorEnvelope
  • 401UNAUTHENTICATED: no session, or the access token expired. application/json · ErrorEnvelope
  • 403FORBIDDEN: the account lacks settings:manage, or the library, label, age or schedule scope refuses it. application/json · ErrorEnvelope
DELETE/auth/ldap/links/{userId}#

Unlink an account from its person in the directory

Its next directory sign-in finds the account by its email again, and links whoever that is.

Authorisation
Bearer token or API key · Session cookie
ParameterInTypeDescription
userId requiredpathstring (uuid)
  • 204Done; no body.
  • 401UNAUTHENTICATED: no session, or the access token expired. application/json · ErrorEnvelope
  • 403FORBIDDEN: the account lacks settings:manage, or the library, label, age or schedule scope refuses it. application/json · ErrorEnvelope
  • 404NOT_FOUND: no such thing, or not one the caller may see. NOT_FOUND: the account does not sign in by the directory application/json · ErrorEnvelope
POST/auth/ldap/login#

Sign in with a directory (LDAP) username and password

Into an account that exists here, never a new one (P7-24): the directory finds the person and checks the password; the account is the one their entry was linked to the first time, else the one their email names (or their username, if the server says so). The password form’s limits, lock and two-step sign-in all hold, and its rate-limit buckets are shared. The owner never signs in this way; an admin only when allowAdmins is on. Only while directory sign-in is on (directorySignIn in GET /server/info).

Authorisation
None
Body
application/json · object
  • 200Success. application/json · SignInAnswer
  • 400VALIDATION_FAILED: the request did not match the schema; details.issues lists what. application/json · ErrorEnvelope
  • 401AUTH_INVALID_CREDENTIALS: nobody by that username, or a wrong password AUTH_2FA_REQUIRED: the directory vouched and a second factor is owed; details carries the challenge for POST /auth/2fa/verify application/json · ErrorEnvelope
  • 403AUTH_NO_ACCOUNT: no account here uses the email the directory gives (details.reason none); its email was chosen by whoever accepted its invitation, so an admin links it (unvouched); it answers to someone else in the directory, or two accounts match (linked-elsewhere, ambiguous); or the person at a DN-kept link no longer has its email (moved) AUTH_PASSWORD_REQUIRED: the owner, or an admin while allowAdmins is off: they sign in with their own password AUTH_ACCOUNT_LOCKED: too many failures; try again later FORBIDDEN: not in the required group (details.reason is ldap-group) application/json · ErrorEnvelope
  • 404NOT_FOUND: directory sign-in is off application/json · ErrorEnvelope
  • 429RATE_LIMITED: more than 10 attempts in a minute, by address, name or person application/json · ErrorEnvelope
  • 502PROVIDER_UNAVAILABLE: the directory could not be reached over TLS application/json · ErrorEnvelope
POST/auth/ldap/test#

Try directory settings, and look someone up

The settings as the form has them (what is left out, as saved): reaches the directory over TLS, signs in as the search account, and looks for the username given — never with their password — saying which account it would sign in to and how (person.link). The kept search password is used only with the addresses, account and certificate settings it was saved with; with others, a bindPassword must be typed, or the test stops at settings. Says where it stopped and why.

Authorisation
Bearer token or API key · Session cookie
Body
application/json · object
  • 200Success. application/json · object
  • 400VALIDATION_FAILED: the request did not match the schema; details.issues lists what. application/json · ErrorEnvelope
  • 401UNAUTHENTICATED: no session, or the access token expired. application/json · ErrorEnvelope
  • 403FORBIDDEN: the account lacks settings:manage, or the library, label, age or schedule scope refuses it. application/json · ErrorEnvelope
POST/auth/login#

Sign in with a password

Bearer clients receive tokens in the body (accessToken, refreshToken, refreshExpiresAt). The web client sends cookieMode: true and receives HttpOnly cookies instead. Rate limited to 10/min per IP and per username. A browser holding an outside identity that waits for this account’s own password (the co_identity_link cookie an outside sign-in left, docs/11 §5) has it linked to the account — only the account that identity’s email named, once any second factor is in.

Authorisation
None
Body
application/json · object
  • 200Success. application/json · SignInAnswer
  • 400VALIDATION_FAILED: the request did not match the schema; details.issues lists what. application/json · ErrorEnvelope
  • 401AUTH_INVALID_CREDENTIALS: the username or password is wrong AUTH_2FA_REQUIRED: the password was right and a second factor is owed; details carries the challenge application/json · ErrorEnvelope
  • 403AUTH_ACCOUNT_LOCKED: too many failures; try again later application/json · ErrorEnvelope
  • 429RATE_LIMITED: more than 10 attempts in a minute application/json · ErrorEnvelope
POST/auth/logout#

End the session

Authorisation
None
Body
application/json · object
  • 200Success. application/json · object
  • 400VALIDATION_FAILED: the request did not match the schema; details.issues lists what. application/json · ErrorEnvelope
GET/auth/me#

Read the signed-in account

Authorisation
Bearer token or API key · Session cookie
  • 200Success. application/json · PublicUser
  • 401UNAUTHENTICATED: no session, or the access token expired. application/json · ErrorEnvelope
  • 403FORBIDDEN: the account may not do this. application/json · ErrorEnvelope
PATCH/auth/me#

Change your own display name

The one part of your own account you may change without users:manage. The whole public user comes back, as GET /auth/me answers it.

Authorisation
Bearer token or API key · Session cookie
Body
application/json · object
  • 200Success. application/json · PublicUser
  • 400VALIDATION_FAILED: the request did not match the schema; details.issues lists what. application/json · ErrorEnvelope
  • 401UNAUTHENTICATED: no session, or the access token expired. application/json · ErrorEnvelope
  • 403FORBIDDEN: the account may not do this. application/json · ErrorEnvelope
POST/auth/me/password#

Change your own password

The current password proves it is you. Every session ends, this one included — sign in again with the new password. Not for an API key.

Authorisation
Bearer token or API key · Session cookie
Body
application/json · object
  • 204Done; no body.
  • 400VALIDATION_FAILED: the request did not match the schema; details.issues lists what. application/json · ErrorEnvelope
  • 401UNAUTHENTICATED: no session, or the access token expired. AUTH_INVALID_CREDENTIALS: the current password is wrong application/json · ErrorEnvelope
  • 403FORBIDDEN: the account may not do this. application/json · ErrorEnvelope
PATCH/auth/me/prefs#

Update the account’s preferences

Only what the body names changes. Some preferences are Collectoh Plus’s (docs/14 §6): a theme other than the default, a colour scheme other than dark, a subtitle style, and a sidebar order or pins of the account’s own. Without Plus, changing to one is refused; going back to the default, or sending again what is kept, never is.

Authorisation
Bearer token or API key · Session cookie
Body
application/json · object
  • 200Success. application/json · PublicUser
  • 400VALIDATION_FAILED: the request did not match the schema; details.issues lists what. application/json · ErrorEnvelope
  • 401UNAUTHENTICATED: no session, or the access token expired. application/json · ErrorEnvelope
  • 402PLUS_REQUIRED: the body changes a preference only Plus applies, on a server without it; details.feature is themes, subtitle-styles or sidebar-order application/json · ErrorEnvelope
  • 403FORBIDDEN: the account may not do this. application/json · ErrorEnvelope
GET/auth/private#

Say whether private libraries are unlocked on this device

Authorisation
Bearer token or API key · Session cookie
  • 200Success. application/json · object
  • 401UNAUTHENTICATED: no session, or the access token expired. application/json · ErrorEnvelope
  • 403FORBIDDEN: the account may not do this. application/json · ErrorEnvelope
POST/auth/private/lock#

Lock private libraries again on this device

Authorisation
Bearer token or API key · Session cookie
  • 200Success. application/json · object
  • 401UNAUTHENTICATED: no session, or the access token expired. application/json · ErrorEnvelope
  • 403FORBIDDEN: the account may not do this. application/json · ErrorEnvelope
POST/auth/private/unlock#

Unlock private libraries for an hour, with the account password

Authorisation
Bearer token or API key · Session cookie
Body
application/json · object
  • 200Success. application/json · object
  • 400VALIDATION_FAILED: the request did not match the schema; details.issues lists what. application/json · ErrorEnvelope
  • 401UNAUTHENTICATED: no session, or the access token expired. AUTH_INVALID_CREDENTIALS: the password is wrong (403: the session stands) application/json · ErrorEnvelope
  • 403FORBIDDEN: the account may not do this. FORBIDDEN: a child or a guest, who never unlocks them application/json · ErrorEnvelope
GET/auth/profiles#

List the profiles this session may switch to

Authorisation
Bearer token or API key · Session cookie
  • 200Success. application/json · SwitchableProfile[]
  • 401UNAUTHENTICATED: no session, or the access token expired. application/json · ErrorEnvelope
  • 403FORBIDDEN: the account may not do this. application/json · ErrorEnvelope
POST/auth/profiles/{id}/switch#

Switch to another profile

Authorisation
Bearer token or API key · Session cookie
Body
application/json · object
ParameterInTypeDescription
id requiredpathstring (uuid)
  • 200Success. application/json · SignInAnswer
  • 400VALIDATION_FAILED: the request did not match the schema; details.issues lists what. application/json · ErrorEnvelope
  • 401UNAUTHENTICATED: no session, or the access token expired. AUTH_PIN_INVALID: the profile has a PIN and it was wrong application/json · ErrorEnvelope
  • 403FORBIDDEN: the account may not do this. AUTH_PASSWORD_REQUIRED: an owner, an admin or an account with two-step sign-in: it signs in with its password application/json · ErrorEnvelope
  • 404NOT_FOUND: no such thing, or not one the caller may see. application/json · ErrorEnvelope
  • 429RATE_LIMITED: five wrong PINs for the profile in a quarter of an hour application/json · ErrorEnvelope
POST/auth/refresh#

Rotate the refresh token

Refresh tokens rotate on every use. Reusing a rotated token revokes the whole chain (AUTH_TOKEN_REUSED). An app sends its refresh token in the body and gets the new pair in the answer; the web client sends none (its cookie carries it) and gets cookies.

Authorisation
None
Body
application/json · object
  • 200Success. application/json · SignInAnswer
  • 400VALIDATION_FAILED: the request did not match the schema; details.issues lists what. application/json · ErrorEnvelope
  • 401AUTH_TOKEN_EXPIRED: the refresh token is older than 30 days AUTH_TOKEN_REUSED: a rotated token was presented again application/json · ErrorEnvelope
POST/auth/reset#

Set a new password from a reset link

Authorisation
None
Body
application/json · object
  • 200Success. application/json · AuthSession
  • 400VALIDATION_FAILED: the request did not match the schema; details.issues lists what. application/json · ErrorEnvelope
GET/auth/reset/{token}#

Read what a reset link is for

Authorisation
None
ParameterInTypeDescription
token requiredpathstring
  • 200Success. application/json · object
  • 404NOT_FOUND: no such thing, or not one the caller may see. application/json · ErrorEnvelope
GET/auth/sign-in/{provider}#

Start an outside sign-in

Redirects to the provider (Collectoh, Google, Apple, an OpenID issuer), leaving a cookie that ties the sign-in to this browser. Only configured providers answer; one that is not answering sends the browser to the login page with the error.

Authorisation
None
ParameterInTypeDescription
provider requiredpathstring
nextquerystring
promptquery"none"
clientquerystring
clientNamequerystring
  • 302Success.
  • 400VALIDATION_FAILED: the request did not match the schema; details.issues lists what. application/json · ErrorEnvelope
  • 404NOT_FOUND: no such thing, or not one the caller may see. application/json · ErrorEnvelope
GET/auth/sign-in/{provider}/callback#

Finish an outside sign-in

Redirects into the app with a session, or to the login page with an error. Only the browser that started the sign-in finishes it. An identity signs in the account it was linked to, whatever the emails say; the first time, the account carrying the email it vouches for, linked once the sign-in goes through — when whoever runs the server gave the account that email. One its holder chose as they accepted an invitation sends the browser to /login?error=AUTH_LINK_REQUIRED&provider=… with the identity waiting in an HttpOnly cookie (co_identity_link, a quarter of an hour) for that account’s own password (POST /auth/login); asked quietly (prompt=none), it comes back with nothing. An account that answers to another identity there: /login?error=AUTH_NO_ACCOUNT&reason=linked-elsewhere&provider=….

Authorisation
None
ParameterInTypeDescription
provider requiredpathstring
  • 302Success.
  • 404NOT_FOUND: no such thing, or not one the caller may see. application/json · ErrorEnvelope
POST/auth/sign-in/{provider}/callback#

Finish an outside sign-in (form post)

Only for a provider that answers by POST (Apple, response_mode=form_post), as a form, from the browser that started it (its co_sign_in_post cookie, SameSite=None); otherwise as the GET.

Authorisation
None
ParameterInTypeDescription
provider requiredpathstring
  • 302Success.
  • 404NOT_FOUND: no such thing, or not one the caller may see. application/json · ErrorEnvelope