Skip to content

API reference

All API endpoints require an API token with the matching scope:

Authorization: Bearer <PLAIN_TOKEN>

Responses are JSON. A missing or invalid token results in 401, a token without the required scope in 403.

Dovecot

Scope dovecot. Used by the Dovecot Lua adapter.

Method Path Description
GET /api/dovecot/status Health check. Returns {"message": "success"}.
GET /api/dovecot/{email} userdb lookup.
POST /api/dovecot/{email} passdb lookup: verify the password.

userdb lookup response:

{
  "message": "success",
  "body": {
    "user": "user@example.org",
    "mailCrypt": 2,
    "mailCryptPublicKey": "<base64>",
    "quota": "1024M"
  }
}

mailCrypt is 2 if MailCrypt is enabled for the user, otherwise 0. quota is empty if no quota is set. Unknown and deleted users return 404.

passdb lookup request and response:

{ "password": "<password>" }
{
  "message": "success",
  "body": {
    "mailCrypt": 2,
    "mailCryptPrivateKey": "<base64>",
    "mailCryptPublicKey": "<base64>"
  }
}
Status Meaning
200 Authenticated
401 Wrong password, or the main password of a 2FA user if app passwords are required
403 Password change required
404 Unknown or deleted user
500 MailCrypt key could not be decrypted

Postfix

Scope postfix. Used by the Postfix adapter.

Method Path Response
GET /api/postfix/domain/{domain} true if the domain is managed by Userli
GET /api/postfix/mailbox/{email} true if an active user with this address exists
GET /api/postfix/alias/{email} List of destinations of the alias, e.g. ["user@example.org"]
GET /api/postfix/senders/{email} List of users allowed to send with this address
GET /api/postfix/smtp_quota/{email} {"per_hour": 100, "per_day": 1000, "sending_allowed": true, "allowed_recipients": []}, 0 = unlimited. If sending_allowed is false (role Spam), the user may only send to the addresses in allowed_recipients (the support address). 404 for unknown users
POST /api/postfix/auth SMTP authentication, body {"email": "...", "password": "..."}

auth status codes: 200 success, 401 authentication failed (also the main password of a 2FA user if app passwords are required), 403 password change required.

Roundcube

Scope roundcube. Used by the Roundcube plugin.

Method Path Description
POST /api/roundcube/aliases Body {"email": "...", "password": "..."}. Returns the list of the user's alias addresses. 401 on wrong credentials. App passwords are rejected.
POST /api/roundcube/login Body {"email": "...", "password": "...", "code": "..."}. Checks the main password and, if the user has two-factor authentication, the TOTP or backup code in code. Returns {"password": "...", "expiresAt": "<ISO 8601>"}, a webmail credential that is valid for 12 hours in Dovecot and Postfix. 401 with message twofactor required if code is missing, authentication failed otherwise. 403 for users with a required password change, only after the password is correct. 422 for an invalid body. 500 if the MailCrypt key can't be decrypted. App passwords are rejected.
POST /api/roundcube/logout Body {"email": "...", "password": "<webmail credential>"}. Revokes the webmail credential. Always returns 204.

Keycloak

Scope keycloak. Used by the Keycloak user provider.

Method Path Description
GET /api/keycloak/{domain}?search=&max=10&first=0 Search users. Returns [{"id": "<local part>", "email": "..."}].
GET /api/keycloak/{domain}/count Number of users in the domain.
GET /api/keycloak/{domain}/user/{email} Get a single user.
POST /api/keycloak/{domain}/validate/{email} Validate a credential, body {"credentialType": "password"\|"otp", "password": "..."}. App passwords are rejected.
GET /api/keycloak/{domain}/configured/{credentialType}/{email} Whether the user has the credential type (e.g. otp) configured.

For otp, password is the 6-digit TOTP code or a backup code – a matching backup code is consumed. See Keycloak for status codes.

Retention

Scope retention. See Retention.

Method Path Description
PUT /api/retention/{email}/touch Update the last login time. Optional body {"timestamp": <unix time>}; 400 if in the future.
GET /api/retention/users List users without login for two years.

Public endpoints

No authentication required.

Method Path Description
GET /.well-known/openpgpkey/{domain}/hu/{hash} Web Key Directory: binary OpenPGP key
GET /.well-known/openpgpkey/{domain}/policy Web Key Directory policy (empty)
GET /.well-known/mta-sts.txt MTA-STS policy for the domain in the Host header