REST API

Scripts and other programs can manage a Reqad server over HTTPS: list, create, change and delete hosting accounts, databases and mailboxes, start Git deployments, and read what needs attention. They send JSON, get JSON back and use the same code as the panel and the command line, so an account created through the API is set up the same way as one created in the browser.

Off until you turn it on. First make it available with api=1 in /usr/local/reqad/etc/server-software.ini: the Settings > API access page then appears in the panel. Turn the API on there, or run reqad api on as root. While the API is off, every request is refused. Your tokens are kept. With api=0 (the default) the page, reqad api and every request are refused; Git deploy webhooks keep working.

To manage the server from an AI assistant, you do not need the API: see AI assistants (MCP).

Access tokens

Each request carries a token in the Authorization header. The panel login is never used, so the API keeps working with two-factor authentication, passkeys and browser sessions as they are. Make tokens under Settings > API access > New token, after confirming your password, or with reqad api new. A token has:

SettingWhat it does
ForThe whole server, or one hosting account. An account token sees and changes only what that account owns: its own databases, mailboxes and problems. It cannot create or delete accounts, turn mail on or off, or change the shell type.
PermissionsEvery token can read. Create and change (write) and Delete (delete) are added one at a time, so a monitoring script can only read and a billing system can create accounts without being able to delete them.
Expires after30 days, 90 days (the default), a year, or never.
Allowed fromOptional: addresses or networks the token works from, e.g. 203.0.113.7, 198.51.100.0/24. Requests from anywhere else are refused.

The token is shown only once, when you make it. The server keeps a fingerprint of the token, not the token itself, so it cannot show it again. If you lose a token, revoke it and make a new one. Revoke takes effect at once.

First request

TOKEN=rqd_...    # the token from Settings > API access
curl -H "Authorization: Bearer $TOKEN" https://server.example.com:2087/api/v1/

The reply describes the server and your token, and lists every endpoint. Every reply has the same shape, the same as reqad ... --json on the command line:

{
    "ok": true,
    "message": "Account bob successfully created.",
    "warnings": [],
    "error": "",
    "data": { ... }
}

When ok is false, error says why. A change that went through but needs attention, for example a certificate that could not be issued yet, comes back with ok: true and a note in warnings.

Endpoints

All paths start with https://<your server>:2087/api/v1. Send request bodies as JSON or as form fields.

RequestPermissionWhat it does
GET /readThis server, your token and the list of endpoints.
GET /serverread, serverThe server: OS, Reqad version, uptime, load, memory, disks, web server, PHP versions, number of accounts, mail queue size and the Needs attention counts.
GET /servicesread, serverThe services and timers of the Services page, each with its state, whether it starts at boot, and since when it runs.
POST /services/{name}/restartwrite, serverRestart one of those services. If it does not start again, the answer has its last journal lines.
GET /accountsreadHosting accounts.
POST /accountswrite, serverCreate an account. Body: user, domain, password, quota (MB), php, shell (full, jailed or none), and dns, letsencrypt, email, www as true/false.
GET /accounts/{user}readOne account: PHP version, shell, mailboxes, databases and limits.
PATCH /accounts/{user}writeChange password or php ("8.3", or "off"). With a server token you can also change email (true/false) and shell.
DELETE /accounts/{user}delete, serverDelete an account with its files, mail and databases.
GET /databasesreadMySQL/MariaDB databases with their owner, size and users. ?account=bob shows one account's.
POST /databaseswriteCreate <account>_<name> and its user. Body: account, name, dbuser (default: the name), password.
DELETE /databases/{name}deleteDrop a database, and its users that have no other database.
POST /database-users/{user}/passwordwriteSet a database user's password. Body: password.
GET /mailboxesreadMailboxes. ?domain=example.com shows one domain's.
POST /mailboxeswriteCreate a mailbox. Body: email, password.
PATCH /mailboxes/{email}writeChange password, or block or allow login with enabled (true/false). Mail is still delivered while login is blocked.
DELETE /mailboxes/{email}deleteDelete a mailbox and its mail.
GET /mail-queueread, serverThe outgoing mail queue: total, frozen, the senders and recipient domains with the most messages, and the oldest messages with their subjects. ?filter=frozen, ?search= (sender or recipient), ?limit= (default 50).
POST /mail-queue/{id}/deliverwrite, serverTry to deliver one queued message now; the answer has what the mail server said.
DELETE /mail-queue/{id}delete, serverRemove a message from the queue without delivering it.
GET /logsreadThe logs you can read: a domain's web requests and errors (site) and PHP errors (php), and with a server token the web server, mail (mail, mail-reject, mail-panic), IMAP/POP3, firewall, SSH, cron, system and panel logs.
GET /logs/{name}readThe last lines of a log. ?lines= (default 100, at most 1000), ?grep= only lines containing that text, ?domain= for site and php. A token for one account reads only its own domains' site and PHP logs.
GET /wordpressreadWordPress sites with the version the last check saw. ?account=bob shows one account's.
GET /wordpress/{site}readOne site (its id, domain or account) read live: WordPress version and whether it is the latest, core updates, and every plugin and theme with its version and available update. ?refresh=1 asks wordpress.org again first.
POST /wordpress/{site}/updatewriteUpdate what: core, plugins or themes; items names plugins or themes (default: all with an update). The site's database is saved to ~/wp-backups/ first (compressed).
POST /wordpress/{site}/plugins/{plugin}/activate, /deactivatewriteTurn a plugin on or off.
POST /wordpress/{site}/purge-cachewriteEmpty the site's caches: nginx page cache, OPcache, the object cache, cache plugins (WP Rocket, LiteSpeed, W3 Total Cache, WP Super Cache and others) and Elementor's CSS. Updates and plugin changes do this on their own.
GET /wordpress/{site}/verifyreadCompare core and plugin files with the wordpress.org checksums.
GET /deploymentsreadGit deployments. ?account=bob shows one account's.
GET /deployments/{id}readOne deployment (its id or domain) with the releases on disk and the latest runs.
POST /deployments/{id}/deploywriteDeploy the branch now, e.g. from CI. Returns the run id.
POST /deployments/{id}/rollbackwriteSwitch back to an earlier release. Body: release (default: the one before the current).
GET /deploy-runs/{run}readA run's status and output; ?offset= returns only what was added since.
GET /appsreadNode.js and Python apps with their state. ?account=bob shows one account's.
GET /apps/{id}readOne app (its id or domain): settings, state, memory, restarts.
POST /apps/{id}/start, /stop, /restartwriteStart, stop or restart an app.
GET /apps/{id}/logsreadWhat the app printed lately; ?lines= (default 200).
GET /healthreadWhat needs attention, most serious first. ?account=bob shows one account's problems, ?account=- the server's own. ?all=1 includes hidden problems.
GET /health/checksreadThe checks that run.
POST /health/runwrite, serverRun the checks now. This takes a few seconds.
POST /health/dismisswriteHide a problem. Body: id, and days (default 7) or forever: true.
POST /health/restorewriteShow a hidden problem again. Body: id.

server means a token for the whole server is required. A token for one account gets 403.

Passwords: when you create an account, database or mailbox, or set a database user's password, and leave password out, the server generates a strong password and returns it once in data.password.

Examples

API=https://server.example.com:2087/api/v1
AUTH="Authorization: Bearer $TOKEN"

# create an account with a generated password, PHP 8.3 and a certificate
curl -H "$AUTH" -d '{"user":"bob","domain":"bob.example","php":"8.3","letsencrypt":true}' $API/accounts

# a database for it
curl -H "$AUTH" -d '{"account":"bob","name":"wp"}' $API/databases

# a mailbox, then block its login
curl -H "$AUTH" -d '{"email":"info@bob.example"}' $API/mailboxes
curl -H "$AUTH" -X PATCH -d '{"enabled":false}' $API/mailboxes/info@bob.example

# anything critical? (for monitoring)
curl -s -H "$AUTH" $API/health | jq '.data.counts.critical'

Status codes

CodeMeaning
200 / 201Done (201: something was created).
400The request was understood, but the change was refused. For example, the name is taken or the password is too short. error says why.
401No token, a wrong token, or one that was revoked or has expired.
403The token is valid but may not do this: a missing permission, another account's resource, an address not on its list. Also returned while the API is off.
404 / 405No such resource or endpoint, or the wrong method for it.
409The feature is turned off on this server (e.g. email).
429Too many requests, or too many wrong tokens, from your address. See Retry-After.

Security

  • A wrong token counts as a failed login. After 5, the address is locked out of the API and the panel login for 15 minutes; after more, the firewall blocks it, as for the login page. A revoked or expired token is refused without counting, so a forgotten script does not get your own address blocked.
  • The API accepts tokens only, never browser cookies. A web page you visit while logged in to the panel cannot use your session to call the API.
  • Each address may make about 120 requests a minute.
  • Settings > API access shows the latest calls (kept for 30 days) and when and from where each token was last used. The security log records tokens being made and revoked, wrong tokens, and a token used from a new address.
  • When the panel's IP restriction is on (Settings > Security), port 2087 answers only the listed addresses. Add the addresses your scripts call from.
  • Give each program its own token with the fewest permissions it needs. Use an account token when a program works for one customer.

On the command line

reqad api status                     # on or off, the address, active tokens
reqad api on                         # or: off
reqad api new monitoring             # read-only, expires in 90 days
reqad api new billing --write --days=365 --ip=203.0.113.7
reqad api new bob-deploy --account=bob --write
reqad api tokens                     # --all also lists revoked tokens
reqad api revoke billing
reqad api log --lines=50

See Command line (CLI) for every option.


Need a hand? Create a free account or contact us.