Skip to main content
Version: 1.X.X

OpenAdmin API Documentation

OpenAdmin API can be used to manage options available from the OpenAdmin interface: hosting plans, accounts, domains, services, DNS, email, security, server administration, and more. All API endpoints require Bearer JWT authentication.

INFORMATION

OpenAdmin API is available only on OpenPanel Enterprise edition. To use the API, enable it first from the OpenAdmin > Settings > API Access page or from terminal with opencli api on command.

To generate a token for use with the endpoints, send a POST request to /api/ using your OpenAdmin username and password:

curl -X POST "https://OPENADMIN_DOMAIN_OR_IP:2087/api/" && \
-H "Content-Type: application/json" -d '{"username":"OPENADMIN_USERNAME","password":"OPENADMIN_PASSWORD"}'

We recommend creating a separate admin user dedicated solely to API usage. This way, you can quickly suspend or delete that account if its credentials are ever compromised.

Example response with the token is:

{"access_token":"eyJhbGciOiJIUzI1NiIsInRs4CI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTc4MDc0OTkwOCwianRpIjoiZDcwZmY2NmEtNDNiOC00OGZkLThiMWEtZDIwYWUwMDNhNjEyIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6Im9wc3VwcG9ydCIsIm5iZiI6MTc4MDc0OTkwOCwiY3NyZiI6IjZlOGRmNGVmLTA0MjktNGNkYy1hNTg5LTJkYzUwMDk2ZDI2NSIsI3V4cCI6MTc4M33c1MDgwOH0.WLQ8rsVOF6pQg07i1fI1lXfd8_cCmryiOjGqg8zgOmw"}

This token must be sent in header for all other API endpoints:

-H "Authorization: Bearer YOUR_JWT_TOKEN" -H "Content-Type: application/json"

๐Ÿ’ก Hint: Use opencli api list command to view usage examples for all the endpoints available on your OpenPanel version.

DANGER

Some endpoints below are destructive or high-privilege (rebooting the server, changing the root SSH password, disabling OpenAdmin, migrating a server, WAF/firewall management). They run with the same privilege as the admin panel itself โ€” scope and rotate API tokens accordingly.


Usersโ€‹

List All Accountsโ€‹

GET /api/users

Example response
[
{
"username": "stefan",
"email": "[email protected]",
"plan_name": "default_plan_nginx"
}
]

Create Accountโ€‹

POST /api/users Request Body:

{
"email": "[email protected]",
"username": "stefan",
"password": "s32dsasaq",
"plan_name": "default_plan_nginx"
}

Response:

{
"response": {
"message": "Successfully added user stefan password: s32dsasaq"
},
"success": true
}

Get Single Accountโ€‹

GET /api/users/{username}

Suspend / Unsuspend / Change Passwordโ€‹

PATCH /api/users/{username} Request Body Example:

{
"action": "suspend",
"password": "NEW_PASSWORD_HERE"
}

Change Planโ€‹

PUT /api/users/{username} Request Body:

{
"plan_name": "default_plan_nginx"
}

Delete Accountโ€‹

DELETE /api/users/{username}

Autologin to User Accountโ€‹

CONNECT /api/users/{username}

List Users with Dedicated IPsโ€‹

GET /api/ips

List a User's Containersโ€‹

GET /api/users/{username}/containers

Add ?stats=1 to get live CPU/memory/network stats for that user's containers instead of the compose service definitions.

Manage a User's Containerโ€‹

POST /api/users/{username}/containers/{action}/{container_name}

{action} is one of start, stop, restart, cpu, ram.

Request Body (for cpu/ram only):

{
"value": "2"
}

Plansโ€‹

List All Plansโ€‹

GET /api/plans Response:

{
"plans": [
{
"id": 1,
"name": "ubuntu_nginx_mysql",
"description": "Unlimited disk space and Nginx",
"bandwidth": 100,
"cpu": "1",
"ram": "1g",
"disk_limit": "10 GB",
"storage_file": "0 GB",
"inodes_limit": 1000000,
"db_limit": 0,
"domains_limit": 0,
"websites_limit": 10,
"docker_image": "openpanel/nginx"
}
]
}

Create Planโ€‹

POST /api/plans Request Body:

{
"name": "Starter",
"description": "Starter hosting plan",
"email_limit": "10",
"max_email_quota": "0",
"max_hourly_email": "0",
"ftp_limit": "5",
"domains_limit": "5",
"websites_limit": "5",
"disk_limit": "5000",
"inodes_limit": "100000",
"db_limit": "5",
"cpu": "1",
"ram": "1",
"bandwidth": "100",
"feature_set": "default"
}

Get Single Planโ€‹

GET /api/plans/{plan_id}

Edit Planโ€‹

PUT /api/plans/{plan_id} (or PATCH) Request Body: same fields as Create Plan โ€” only send the ones you want to change, the rest fall back to defaults (0 for limits, 1 for cpu/ram, 100 for bandwidth, default for feature_set).

Delete Planโ€‹

DELETE /api/plans/{plan_id}


Domainsโ€‹

List All Domainsโ€‹

GET /api/domains

Add Domainโ€‹

POST /api/domains/new Request Body:

{
"username": "current_user",
"domain": "example.com",
"docroot": "/var/www/html/example.com"
}

Suspend Domainโ€‹

POST /api/domains/suspend/{domain}

Unsuspend Domainโ€‹

POST /api/domains/unsuspend/{domain}

Delete Domainโ€‹

POST /api/domains/delete/{domain}

View / Update Docrootโ€‹

GET /api/domains/docroot/{domain} POST /api/domains/docroot/{domain} Request Body:

{
"docroot": "/var/www/html/newroot"
}

View / Update DNS Zone Fileโ€‹

GET /api/domains/{domain}/dns POST /api/domains/{domain}/dns

Edits the raw bind zone file. On save the zone is validated with named-checkzone and reloaded โ€” if validation fails, the previous version is restored automatically.

Request Body:

{
"content": "$TTL 86400\n@ IN SOA ..."
}

View / Update Caddy Config for a Domainโ€‹

GET /api/domains/{domain}/caddy POST /api/domains/{domain}/caddy

Same validate-then-reload behavior as the DNS zone endpoint, but for the domain's Caddy config block.

Request Body:

{
"content": "example.com {\n reverse_proxy ...\n}"
}

View / Update VirtualHost Configโ€‹

GET /api/domains/{domain}/vhost/{username} POST /api/domains/{domain}/vhost/{username}

Updates the raw nginx/apache/openresty vhost file for that user's domain and restarts the webserver container.

Request Body:

{
"content": "..."
}

SSL: View Status, Request AutoSSL, Upload Custom Cert, View Logsโ€‹

GET /api/domains/{domain}/ssl POST /api/domains/{domain}/ssl

Request Body (AutoSSL):

{ "action": "autossl" }

Request Body (custom certificate โ€” paths must live under /var/www/html/):

{
"action": "custom",
"public_path": "/var/www/html/example.com/cert.pem",
"private_path": "/var/www/html/example.com/key.pem"
}

Request Body (issuance logs):

{ "action": "logs" }

View Domain Access Logโ€‹

GET /api/domains/{domain}/log

Supports ?page=N and ?show_all=true query params for pagination.

View Domain GoAccess Statsโ€‹

GET /api/domains/{domain}/stats/{username}

Returns the pre-rendered GoAccess HTML report (regenerated every 24h).

DNS Clusterโ€‹

GET /api/dns/cluster โ€” view cluster config (allowed slave IPs, enabled state) POST /api/dns/cluster โ€” enable/disable the cluster, or add/remove a slave IP

Request Body examples:

{ "action": "create", "ip": "1.2.3.4" }
{ "action": "delete", "ip": "1.2.3.4" }
{ "action": "enable" }

DNS Cluster Node Statusโ€‹

GET /api/dns/cluster/{ip}

Checks reachability of a slave node via rndc first, falling back to SSH.

DNS Zone Templatesโ€‹

GET /api/dns/zone-templates POST /api/dns/zone-templates Request Body:

{
"zone_template_ipv4": "...",
"zone_template_ipv6": "..."
}

Domain File Templatesโ€‹

GET /api/domains/file-templates POST /api/domains/file-templates

Default templates used for new domains: default_page, suspended_user, suspended_website, docker_nginx_domain, docker_openresty_domain, docker_apache_domain, docker_varnish, docker_caddy. Send only the keys you want to update.


Usageโ€‹

API Usage Infoโ€‹

GET /api/usage

Current Usage Statsโ€‹

GET /api/usage/stats Response:

{
"usage_stats": "{\"timestamp\": \"2024-09-03\", \"users\": 1, \"domains\": 2, \"websites\": 0}"
}

CPU Usageโ€‹

GET /api/usage/cpu Response Example:

{
"core_0": 0,
"core_1": 0
}

Memory Usageโ€‹

GET /api/usage/memory

Disk Usage Per Userโ€‹

GET /api/usage/disk

Server Disk Usageโ€‹

GET /api/usage/server Response Example:

[
{
"device": "/dev/vda1",
"mountpoint": "/",
"fstype": "ext4",
"total": 123690532864,
"used": 63366230016,
"free": 60307525632,
"percent": 51.2
}
]

Systemโ€‹

Get System Informationโ€‹

GET /api/system Response Example:

{
"hostname": "stefi",
"os": "Ubuntu 24.04 LTS",
"time": "2024-09-04 15:09:16",
"kernel": "6.8.0-36-generic",
"cpu": "DO-Premium-Intel(x86_64)",
"openpanel_version": "0.2.7",
"running_processes": 178,
"package_updates": 98,
"uptime": "18905"
}

Docker Infoโ€‹

GET /api/docker/info

Raw output of the Docker Engine info API call (containers, images, storage driver, etc).


Servicesโ€‹

List Monitored Servicesโ€‹

GET /api/services

Edit Services Listโ€‹

PUT /api/services Request Body Example:

{
"service1": { "name": "Service One", "status": "active" },
"service2": { "name": "Service Two", "status": "inactive" }
}

Check Status of Servicesโ€‹

GET /api/services/status

Start Serviceโ€‹

POST /api/service/start/{service_name}

Restart Serviceโ€‹

POST /api/service/restart/{service_name}

Stop Serviceโ€‹

POST /api/service/stop/{service_name}


Notificationsโ€‹

List Notificationsโ€‹

GET /api/notifications

Response Example:

[
{ "title": "Update available", "message": "New package updates available." }
]

Mark Notification as Readโ€‹

POST /api/notifications/{line_number}/read

Pass ?command=mark_all_as_read to mark every notification as read in one call.

Delete Notificationโ€‹

DELETE /api/notifications/{line_number}

Pass ?command=delete_all to clear the whole log.


Emailsโ€‹

Mailserver Settingsโ€‹

GET /api/emails/settings POST /api/emails/settings

Request Body (set webmail domain):

{ "webmail_domain": "webmail.example.com" }

Request Body (switch webmail client):

{ "webmail_software": "roundcube" }

Request Body (toggle mailserver services โ€” any of ENABLE_POSTFWD, ENABLE_AMAVIS, ENABLE_DNSBL, ENABLE_RSPAMD, ENABLE_SPAMASSASSIN, ENABLE_MTA_STS, ENABLE_OPENDKIM, ENABLE_OPENDMARC, ENABLE_POP3, ENABLE_IMAP, ENABLE_CLAMAV, ENABLE_FAIL2BAN, SMTP_ONLY, ENABLE_SRS):

{ "ENABLE_CLAMAV": "1", "ENABLE_FAIL2BAN": "1" }

Request Body (change storage location โ€” only allowed before any mailbox exists):

{ "storage_type": "custom", "email_storage_location": "/mnt/mail" }

List / Manage Mailboxesโ€‹

GET /api/emails/accounts โ€” list all mailboxes and their quotas POST /api/emails/accounts โ€” update password, quota, or send/receive restrictions DELETE /api/emails/accounts โ€” delete one or more mailboxes

Request Body (change password):

{ "action": "password", "email": "[email protected]", "password": "newpass" }

Request Body (set quota, in MB):

{ "action": "quota-set", "email": "[email protected]", "quota": "1024" }

Request Body (remove quota):

{ "action": "quota-del", "email": "[email protected]" }

Request Body (restrict send/receive):

{ "action": "restrict", "email": "[email protected]", "type": "send", "restrict_action": "add" }

Request Body (delete accounts):

{ "emails": ["[email protected]"] }

Mail Queueโ€‹

GET /api/emails/queue โ€” list queued messages POST /api/emails/queue โ€” retry or delete queued messages

Request Body:

{ "action": "retry", "scope": "all" }
{ "action": "delete", "scope": "selected", "queue_ids": ["ABC123"] }

Per-Domain Email Rate Limitsโ€‹

GET /api/emails/domain-limits โ€” view postfwd rules (add ?hits=example.com to view recent hits for a domain) POST /api/emails/domain-limits โ€” manage rules

Request Body (set a limit):

{ "action": "update-domain", "domain": "example.com", "username": "user1", "limit": 100 }

Request Body (reset counters):

{ "action": "reset-all" }

Other supported actions: reset-domain, reset-user, delete-domain, delete-user, delete-all. You can also send {"raw_content": "..."} to overwrite the postfwd rules file directly.


Securityโ€‹

HTTP Basic Authโ€‹

GET /api/security/basic-auth POST /api/security/basic-auth Request Body:

{
"basic_auth": "yes",
"basic_auth_username": "admin",
"basic_auth_password": "secret"
}

Blacklisted User-Agentsโ€‹

GET /api/security/blacklist-useragents POST /api/security/blacklist-useragents Request Body:

{
"blacklist_useragents": "BadBot\nEvilCrawler",
"enabled": "yes"
}

Disable OpenAdminโ€‹

POST /api/security/disable-admin

DANGER

Irreversible from the web UI/API โ€” the panel can only be re-enabled from the terminal (opencli admin on). Restricted to the Super Administrator.

ConfigServer Firewall (CSF)โ€‹

GET /api/security/firewall โ€” check whether CSF is installed POST /api/security/firewall โ€” forward a raw command to the CSF UI backend

Request Body:

{ "action": "cf" }

CorazaWAF Statusโ€‹

GET /api/security/waf POST /api/security/waf Request Body:

{ "status": "yes" }

CorazaWAF Rule Setsโ€‹

GET /api/security/waf/rules POST /api/security/waf/rules Request Body:

{ "rule_name": "REQUEST-901-INITIALIZATION", "action": "off" }

Two-Factor Authenticationโ€‹

GET /api/security/2fa โ€” returns {"totp_enabled": true}, or a fresh secret + qr_data_uri to scan if 2FA isn't enabled yet POST /api/security/2fa/enable โ€” confirm enrollment POST /api/security/2fa/disable โ€” turn 2FA off

Request Body (enable):

{ "secret": "BASE32SECRET", "code": "123456" }

Request Body (disable):

{ "password": "your-account-password" }

Passkeysโ€‹

GET /api/security/passkeys โ€” list passkeys for the authenticated API user POST /api/security/passkeys โ€” rename a passkey DELETE /api/security/passkeys โ€” remove a passkey

Request Body:

{ "id": 1, "name": "Yubikey" }
INFORMATION

Passkey registration requires a live WebAuthn ceremony in a browser and isn't available over the API โ€” use the OpenAdmin UI to enroll a new key, then manage it here.


Serverโ€‹

Cron Jobsโ€‹

GET /api/server/crons POST /api/server/crons Request Body:

{
"jobs": [
{ "line_number": 1, "schedule": "0 3 * * *", "logging": true }
]
}

SSHโ€‹

GET /api/server/ssh โ€” status, running config, authorized keys, and current settings POST /api/server/ssh โ€” start/stop/restart the service, update settings, or manage authorized keys

Request Body (service action):

{ "action": "restart" }

Request Body (settings):

{ "port": "2222", "password_auth": "no", "pubkey_auth": "yes", "permit_root_login": "no" }

Request Body (add/remove a key):

{ "new_key": "ssh-ed25519 AAAA... comment" }
{ "key_to_remove": "ssh-ed25519 AAAA..." }

SSH Full Configโ€‹

GET /api/server/ssh/config โ€” raw sshd_config POST /api/server/ssh/config โ€” overwrite it (restarts SSH)

Timezoneโ€‹

GET /api/server/timezone POST /api/server/timezone Request Body:

{ "timezone": "Europe/Belgrade" }

Drop Memory Cache / Swapโ€‹

POST /api/server/memory/drop-cache POST /api/server/memory/drop-swap

Process Managerโ€‹

GET /api/server/processes โ€” supports ?sort=cpu|memory|priority|name|owner|command|pid (prefix with - to reverse) POST /api/server/processes/{pid}/kill

Clustering Nodeโ€‹

GET /api/server/node POST /api/server/node Request Body:

{ "default_node": "[email protected]", "default_ssh_key_path": "/root/.ssh/id_rsa" }

Root Passwordโ€‹

POST /api/server/root-password Request Body:

{ "password": "newpassword" }
DANGER

Restricted to the Super Administrator. Changes the actual root SSH password on the server.

Rebootโ€‹

POST /api/server/reboot Request Body:

{ "reboot_type": "graceful" }

reboot_type is graceful (waits, then reboot) or hard (sysrq trigger). The request blocks until the reboot delay elapses, then the connection drops.

GET /api/server/reboot/status โ€” used to poll whether the panel is back up.

Server Migrationโ€‹

GET /api/server/migrate โ€” check status/log of an in-progress or finished migration POST /api/server/migrate โ€” start importing data from another OpenPanel server over SSH

Request Body:

{ "host": "1.2.3.4", "root": "root", "password": "secret" }

Settingsโ€‹

Administratorsโ€‹

GET /api/settings/administrators POST /api/settings/administrators

Request Body (create โ€” Enterprise only):

{ "action": "create", "username": "newadmin", "password": "secret123" }

Other supported actions: suspend, unsuspend, delete, rename_user (with new_username), reset_password (with new_password), disable_2fa, disable_passkeys.

Resellersโ€‹

GET /api/settings/resellers POST /api/settings/resellers

Request Body (create):

{ "action": "create", "username": "reseller1", "password": "secret123" }

Request Body (update limits):

{ "action": "update", "username": "reseller1", "allowed_plans": "1,2", "max_accounts": "10", "max_disk_blocks": "1000" }

Other supported actions: suspend, unsuspend, delete, rename_user, reset_password, disable_2fa, disable_passkeys. A reseller token can only manage its own account and is restricted to reset_password.

General Settingsโ€‹

GET /api/settings/general POST /api/settings/general Request Body:

{ "2083_port": "2083", "2087_port": "2087", "force_domain": "panel.example.com", "dev_mode": "off" }

Defaults for New Accountsโ€‹

GET /api/settings/defaults POST /api/settings/defaults Request Body:

{
"values": { "DEFAULT_PHP_VERSION": "8.2", "WEB_SERVER": "nginx" },
"services": ["phpmyadmin"]
}

Default Compose/Env Templatesโ€‹

GET /api/settings/defaults/files POST /api/settings/defaults/files DELETE /api/settings/defaults/files โ€” resets both files from the upstream GitHub source

Request Body:

{ "env": "...", "compose": "..." }

Per-User Compose/Env Filesโ€‹

GET /api/settings/defaults/files/{username} POST /api/settings/defaults/files/{username}

Feature Setsโ€‹

GET /api/settings/features โ€” list feature sets GET /api/settings/features/{plan} โ€” view one set POST /api/settings/features โ€” create a new set POST /api/settings/features/{plan} โ€” update/enable-all/disable-all/delete a set

Request Body (create):

{ "feature_name": "my_set" }

Request Body (update):

{ "action": "update", "features": ["ftp", "cron"] }

Other actions: enable_all, disable_all, delete.

Localesโ€‹

GET /api/settings/locales POST /api/settings/locales

Request Body (install):

{ "locale": "en-us" }

Request Body (set default):

{ "default": "en-us" }

Modules / Pluginsโ€‹

GET /api/settings/modules POST /api/settings/modules Request Body:

{ "enabled_modules": ["dns", "malware_scan", "phpmyadmin"] }

Custom Codeโ€‹

GET /api/settings/custom-code POST /api/settings/custom-code

Send any of: custom_css, custom_js, in_header, in_footer, post_update, pre_startup, custom_section, forbidden_usernames, restricted_domains, howto_guides, wp_themes, wp_plugins, pagespeed_api_key.

{ "custom_css": "body { background: #111; }" }

PHPโ€‹

GET /api/settings/php POST /api/settings/php Request Body:

{ "php82": "memory_limit=512M\nupload_max_filesize=64M" }

Send "options" to update /etc/openpanel/php/options.txt, or phpXY (php56 โ€ฆ php84) to update a specific version's php.ini.

Caddy Metricsโ€‹

GET /api/settings/caddy/metrics

Returns raw Prometheus-format metrics from Caddy's /metrics endpoint.

Update Preferencesโ€‹

GET /api/settings/updates โ€” current preference, latest available version, and update log POST /api/settings/updates Request Body:

{ "preference": "minor_only" }

preference is one of minor_and_major, minor_only, major_only, none.

Run Update Nowโ€‹

POST /api/settings/updates/now

Starts opencli update --force in the background.

Pin/Downgrade Versionโ€‹

GET /api/settings/updates/tags โ€” list available openpanel/openpanel-ui docker tags POST /api/settings/updates/tags Request Body:

{ "version": "1.7.60" }

Notification Preferencesโ€‹

GET /api/settings/notifications POST /api/settings/notifications Request Body:

{
"cpu": "90",
"webhook_url": "https://example.com/hook",
"update": "on",
"ssh_whitelist": "1.2.3.4/32\n5.6.7.0/24"
}

Supports numeric thresholds (load, cpu, ram, du, swap, max_total_conn, max_conn_per_ip), webhook_url, email, SMTP fields (mail_server, mail_port, mail_use_tls, mail_use_ssl, mail_debug, mail_username, mail_password, mail_default_sender), the services toggle, boolean event toggles (update, attack, limit, login, ssh, reboot, dns, plus the ACTIONS section like admin_create, user_delete, domains_ssl, etc โ€” pass "on"/"off"), and ssh_whitelist (newline-separated IPs/CIDRs).


License & Supportโ€‹

License Keyโ€‹

GET /api/license โ€” current key POST /api/license โ€” set/validate a key DELETE /api/license โ€” remove the license

Request Body:

{ "key": "YOUR-LICENSE-KEY" }

License Infoโ€‹

GET /api/license/info

Verify Licenseโ€‹

POST /api/license/verify

Generate Support Reportโ€‹

GET /api/support/report

Runs opencli report --public --non-interactive and returns the generated report.


Import & Transferโ€‹

Import from cPanel / CyberPanel Backupโ€‹

GET /api/import/{panel_type} โ€” list import job statuses ({panel_type} is cpanel or cyberpanel) POST /api/import/{panel_type} โ€” start an import in the background

Request Body:

{ "path": "/root/backup-user.tar.gz", "plan_name": "default_plan_apache" }

View Import Logโ€‹

GET /api/import/logs/account/{log_filename}

List Detected Backup Filesโ€‹

GET /api/import/backup-files

Scans /, /home, and /root for backup-*.tar.gz files.

OpenPanel-to-OpenPanel Transfersโ€‹

GET /api/import/transfers โ€” list transfer log files POST /api/import/transfers โ€” start a transfer

Request Body:

{
"openpanel_username": "newuser",
"server": "1.2.3.4",
"username": "root",
"password": "secret",
"live_transfer": true
}

Transfer Status for a Userโ€‹

GET /api/import/transfers/{username}

View Transfer Logโ€‹

GET /api/import/logs/transfer/{log_filename}