Skip to main content
Version: 1.7.64

OpenPanel API

OpenPanel exposes a full REST API that mirrors all web UI functionality. Every feature available in the panel can be accessed programmatically.

Authentication​

All API requests require a Bearer token obtained via the login endpoint.

Step 1 — Get a token:

curl -s -X POST https://panel.example.com/api/login \
-H "Content-Type: application/json" \
-d '{"username": "stefan", "password": "yourpassword"}'

Response:

{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 86400
}

Step 2 — Use it on every request:

curl https://panel.example.com/api/account \
-H "Authorization: Bearer eyJhbGciOi..."

Tokens expire after 24 hours. Both api feature AND the specific feature must be enabled in the user's plan.


MySQL​

List databases and users​

GET /api/mysql
Authorization: Bearer <token>
{
"databases": ["mydb", "shop"],
"users": [{"username": "myuser", "host": "%"}]
}

Create a database​

POST /api/mysql
Content-Type: application/json

{"name": "newdb"}

Get database info​

GET /api/mysql/mydb

Drop a database​

DELETE /api/mysql/mydb

List users for a database​

GET /api/mysql/mydb/users

Add user to database​

POST /api/mysql/mydb/users
Content-Type: application/json

{"username": "dbuser", "password": "securepass"}

Remove user from database​

DELETE /api/mysql/mydb/users/dbuser

PostgreSQL​

List databases and users​

GET /api/postgresql

Create a database​

POST /api/postgresql
Content-Type: application/json

{"name": "pgdb"}

Drop a database​

DELETE /api/postgresql/pgdb

List all users​

GET /api/postgresql/users

Create a user​

POST /api/postgresql/users
Content-Type: application/json

{"username": "pguser", "password": "securepass"}

Drop a user​

DELETE /api/postgresql/users/pguser

Assign user to database​

POST /api/postgresql/pgdb/assign/pguser

Revoke user from database​

DELETE /api/postgresql/pgdb/revoke/pguser

Domains​

List all domains​

GET /api/domains
{
"domains": [
{"domain_id": 1, "domain_url": "example.com", "docroot": "/var/www/html"}
]
}

Add a domain​

POST /api/domains
Content-Type: application/json

{"domain": "newdomain.com"}

Remove a domain​

DELETE /api/domains/olddomain.com

Get SSL status​

GET /api/domains/example.com/ssl

Issue / renew SSL​

POST /api/domains/example.com/ssl

Email​

List mailboxes​

GET /api/emails

Create mailbox​

POST /api/emails
Content-Type: application/json

{"email": "[email protected]", "password": "mailpass123"}

Get mailbox details​

GET /api/emails/[email protected]

Change mailbox password​

PATCH /api/emails/[email protected]
Content-Type: application/json

{"password": "newpass456"}

Delete mailbox​

DELETE /api/emails/[email protected]

List aliases​

GET /api/emails/aliases

Create alias​

POST /api/emails/aliases
Content-Type: application/json

{"source": "[email protected]", "destination": "[email protected]"}

Delete alias​

DELETE /api/emails/aliases/[email protected]

Get catch-all address​

GET /api/emails/default/example.com

Set catch-all address​

PUT /api/emails/default/example.com
Content-Type: application/json

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

Check deliverability (all domains)​

GET /api/emails/deliverability

Check deliverability for a domain​

GET /api/emails/deliverability/example.com

Get Sieve mail filters​

GET /api/emails/filters/[email protected]

Update Sieve filters​

PUT /api/emails/filters/[email protected]
Content-Type: application/json

{"rules": "require [\"fileinto\"];\nif header :contains \"Subject\" \"SPAM\" { fileinto \"Junk\"; }"}

FTP​

List FTP accounts​

GET /api/ftp

Create FTP account​

POST /api/ftp
Content-Type: application/json

{"username": "ftpuser", "password": "ftppass", "path": "/var/www/html"}

Delete FTP account​

DELETE /api/ftp/ftpuser

Change FTP password​

PATCH /api/ftp/ftpuser/password
Content-Type: application/json

{"password": "newftppass"}

Change FTP home path​

PATCH /api/ftp/ftpuser/path
Content-Type: application/json

{"path": "/var/www/html/subdir"}

List active FTP connections​

GET /api/ftp/connections

Cron Jobs​

List all cron jobs​

GET /api/crons
{
"jobs": [
{"schedule": "0 * * * *", "command": "/usr/bin/php /var/www/html/cron.php", "valid": true}
]
}

Create a cron job​

POST /api/crons
Content-Type: application/json

{"schedule": "*/5 * * * *", "command": "/usr/bin/php /var/www/html/run.php"}

Edit a cron job​

PATCH /api/crons
Content-Type: application/json

{
"original_schedule": "*/5 * * * *",
"original_command": "/usr/bin/php /var/www/html/run.php",
"schedule": "0 */2 * * *",
"command": "/usr/bin/php /var/www/html/run.php"
}

Delete a cron job​

DELETE /api/crons
Content-Type: application/json

{"schedule": "*/5 * * * *", "command": "/usr/bin/php /var/www/html/run.php"}

Get raw crontab​

GET /api/crons/raw

Save raw crontab​

PUT /api/crons/raw
Content-Type: application/json

{"content": "0 * * * * /usr/bin/php /var/www/html/cron.php\n"}

Tail cron log​

GET /api/crons/log?lines=50&job=cron.php

Cache Services​

Each cache service exposes two endpoints: status and action.

Redis​

GET  /api/cache/redis
POST /api/cache/redis
Content-Type: application/json

{"action": "enable"} # enable | disable | restart

Valkey / Memcached / Elasticsearch / OpenSearch​

Same pattern, replace redis with the service name:

GET  /api/cache/valkey
POST /api/cache/valkey {"action": "disable"}

GET /api/cache/memcached
POST /api/cache/memcached {"action": "restart"}

GET /api/cache/elasticsearch
POST /api/cache/elasticsearch {"action": "enable"}

GET /api/cache/opensearch
POST /api/cache/opensearch {"action": "enable"}

Varnish​

# Status + domain list
GET /api/cache/varnish

# Enable/disable
POST /api/cache/varnish
{"action": "enable"}

# Hit ratio and traffic stats
GET /api/cache/varnish/stats

# Per-domain Varnish status
GET /api/cache/varnish/domains

# Toggle Varnish for a specific domain
POST /api/cache/varnish/domains/example.com
{"status": "On"}

Docker / Containers​

List compose services​

GET /api/containers

List running containers​

GET /api/containers/status

Get single container state​

GET /api/containers/nginx/status

Start / stop / restart​

POST /api/containers/nginx/start
POST /api/containers/nginx/stop
POST /api/containers/nginx/restart

Start with optional pull:

POST /api/containers/nginx/start
{"pull": true}

Update CPU/RAM limits​

PATCH /api/containers/myapp/resources
Content-Type: application/json

{"cpu": "1", "ram": "512m"}

Tail container logs​

GET /api/containers/nginx/logs?lines=200

WAF (Web Application Firewall)​

Status for all domains​

GET /api/waf

Status for a domain​

GET /api/waf/example.com

Toggle WAF on/off​

POST /api/waf/example.com
Content-Type: application/json

{"status": "On"}

Update excluded rules​

PUT /api/waf/example.com/rules
Content-Type: application/json

{
"remove_by_id": ["920170", "941100"],
"remove_by_tag": ["attack-sqli"]
}

Paginated WAF log​

GET /api/waf/log/example.com?page=1&per_page=25

WAF stats​

GET /api/waf/stats/example.com?seconds=3600

List rule IDs / tags​

GET /api/waf/ids/ids
GET /api/waf/ids/tags

IP Blocker​

List blocked IPs​

GET /api/ip-blocker

Block IPs​

POST /api/ip-blocker
Content-Type: application/json

{"ips": ["1.2.3.4", "10.0.0.0/8"]}

Unblock all IPs​

DELETE /api/ip-blocker

PHP​

List installed PHP versions​

GET /api/php/versions

Get php.ini content​

GET /api/php/8.2/ini

Save php.ini​

PUT /api/php/8.2/ini
Content-Type: application/json

{"content": "memory_limit = 256M\nupload_max_filesize = 64M\n..."}

Get PHP option keys and values​

GET /api/php/8.2/options

Update specific PHP options​

PUT /api/php/8.2/options
Content-Type: application/json

{"memory_limit": "256M", "upload_max_filesize": "64M", "max_execution_time": "300"}

List extensions with state​

GET /api/php/8.2/extensions
{
"extensions": [
{"name": "imagick", "state": "active"},
{"name": "redis", "state": "disabled"},
{"name": "swoole", "state": "not_installed"}
]
}

Toggle extension​

POST /api/php/8.2/extensions
Content-Type: application/json

{"extension": "imagick", "action": "enable"}

List all supported extensions​

GET /api/php/8.2/extensions/available

Install an extension​

POST /api/php/8.2/extensions/install
Content-Type: application/json

{"extension": "swoole"}
{"install_id": "swoole_1704067200", "message": "Installation started"}

Poll install status​

GET /api/php/8.2/extensions/install/status?install_id=swoole_1704067200

Account​

Get account info​

GET /api/account
{
"username": "stefan",
"email": "[email protected]",
"plan_id": 1,
"context": "stefan"
}

Update account​

PATCH /api/account
Content-Type: application/json

{"email": "[email protected]"}
# or
{"password": "newpass"}
# or
{"username": "newname"}

List active sessions​

GET /api/account/sessions

Terminate a session​

DELETE /api/account/sessions/<token>

Resource Usage​

Latest snapshot​

GET /api/usage
{
"cpu": {"usage": {"pct": 12.5}},
"memory": {"usage_pct": 45, "used": {"human": "900MB"}, "total": {"human": "2GB"}},
"bandwidth": {"usage_pct": 5, "limit": {"human": "100GB"}}
}

Paginated history​

GET /api/usage/history?page=1&per_page=25

Disk Usage & Inodes​

Disk usage (root)​

GET /api/disk-usage

Disk usage for a path​

GET /api/disk-usage/public_html
{
"directory": "public_html",
"entries": [
{"size": "120M", "path": "wp-content"},
{"size": "3.2M", "path": "wp-includes"}
]
}

Inode count (root)​

GET /api/inodes

Inode count for a path​

GET /api/inodes/public_html

Malware Scanner​

List quarantined files​

GET /api/malware-scanner/quarantine

Run a scan​

POST /api/malware-scanner/scan
Content-Type: application/json

{"directory": "/var/www/html"}
{
"directory": "/var/www/html",
"infected_files": [],
"infected_count": 0,
"summary": ["Scanned files: 1234", "Infected files: 0"],
"return_code": 0
}

Webserver Config​

Get config​

GET /api/webserver-conf
{
"web_server": "nginx",
"label": "Nginx",
"filename": "nginx.conf",
"content": "server { ... }"
}

Save config​

PUT /api/webserver-conf
Content-Type: application/json

{"content": "server {\n listen 80;\n ...\n}"}

Process Manager​

List running processes​

GET /api/process-manager
{
"processes": [
{"container": "nginx", "pid": "1234", "cmd": "nginx: master process", "uid": "0"}
],
"count": 1
}

Kill a process​

DELETE /api/process-manager/1234

Sites & Websites​

List all websites​

GET /api/sites

Get website details​

GET /api/sites/example.com

Google Safe Browsing check​

GET /api/sites/example.com/safebrowsing
{"status": "safe", "url": "http://example.com", "threats": []}

Get PageSpeed data​

GET /api/sites/example.com/pagespeed

Trigger PageSpeed refresh​

POST /api/sites/example.com/pagespeed

Get WP vulnerability data​

GET /api/sites/example.com/wp-vulnerability

Run vulnerability scan​

POST /api/sites/example.com/wp-vulnerability

WordPress​

List all WordPress installations​

GET /api/wordpress

List backups​

GET /api/wordpress/example.com/backups
{
"backups": [
{"date": "2025-01-15_12-00-00", "hasDbBackup": true, "hasFilesBackup": true}
]
}

Create backup​

POST /api/wordpress/example.com/backups
Content-Type: application/json

{"backup_database": true, "backup_files": true}

Restore a backup​

POST /api/wordpress/example.com/restore
Content-Type: application/json

{"backup_date": "2025-01-15_12-00-00"}

List available hardening rules​

GET /api/wordpress/secure
{"rules": ["wp_manager_xmlrpc", "wp_manager_user_enum", "wp_manager_wlwmanifest"]}

Get active hardening rules​

GET /api/wordpress/example.com/secure

Apply hardening rules​

PUT /api/wordpress/example.com/secure
Content-Type: application/json

{"rules": ["wp_manager_xmlrpc", "wp_manager_wlwmanifest"], "disable_all": false}

Disable all rules:

PUT /api/wordpress/example.com/secure
{"disable_all": true}

Uninstall WordPress​

Removes files and drops the database.

DELETE /api/wordpress/sites/42

Detach from WordPress Manager​

Removes from manager, keeps files.

POST /api/wordpress/sites/42/detach

Reload WP data from filesystem​

POST /api/wordpress/reload

WP-CLI actions​

Available actions: core_update, core_update_check, plugin_update_all, theme_update_all, list_plugins, list_themes, cache_flush, cron_run

POST /api/wp-cli/plugin_update_all
Content-Type: application/json

{"domain": "example.com"}
{
"action": "plugin_update_all",
"domain": "example.com",
"stdout": "Success: Updated 3 of 3 plugins.",
"returncode": 0
}

Node.js / Python Apps (PM2)​

Tail app logs​

GET /api/pm2/example.com/logs?lines=100

Start application​

POST /api/pm2/example.com/start

Stop application​

POST /api/pm2/example.com/stop

Restart application (pull + restart)​

POST /api/pm2/example.com/restart

Update app settings​

PATCH /api/pm2/example.com
Content-Type: application/json

{
"version": "20",
"startup_file": "/var/www/html/index.js",
"cpu": "1",
"ram": "1"
}

Delete app​

Stops container, reverts webserver config, removes from docker-compose.yml, and deletes from DB.

DELETE /api/pm2/example.com

Auto Installer​

List installed apps​

GET /api/autoinstaller
{
"sites": [{"site_name": "example.com", "type": "WordPress"}],
"counts": {"wordpress": 1, "node": 0, "python": 0},
"technologies": ["wordpress", "drupal", "node", "python", "...]
}

Dynamic DNS​

List all entries​

GET /api/dynamic-dns
{
"domains": {
"example.com": [
{"subdomain": "home", "record": "1.2.3.4", "token": "abc123xyz", "last_updated": "2025-01-15T12:00:00Z"}
]
}
}

Create entry​

POST /api/dynamic-dns
Content-Type: application/json

{"domain": "example.com", "subdomain": "home", "ip": "0.0.0.0"}
{"entry": {"subdomain": "home", "record": "0.0.0.0", "type": "A", "token": "abc123xyz"}}

Update entry​

PUT /api/dynamic-dns
Content-Type: application/json

{
"domain": "example.com",
"line_number": 42,
"subdomain": "home",
"ip": "1.2.3.4",
"token": "abc123xyz"
}

Delete entry​

DELETE /api/dynamic-dns
Content-Type: application/json

{"domain": "example.com", "line_number": 42}

Auto-update IP (no auth required)​

Called by your router or DDNS client to update the record with the caller's IP:

GET /dynamic-dns/update?token=abc123xyz

DNS Zone Editor​

List domains with zone status​

GET /api/dns

Get parsed DNS records​

GET /api/dns/example.com
{
"domain": "example.com",
"serial": "2025011501",
"records": [
{"line_number": 12, "end_line_number": 12, "line": "www 3600 IN A 1.2.3.4", "multiline": false}
]
}

Get raw zone file​

GET /api/dns/example.com/raw

Save raw zone file​

PUT /api/dns/example.com/raw
Content-Type: application/json

{"content": "$ORIGIN example.com.\n$TTL 3600\n..."}

Add a DNS record​

POST /api/dns/example.com/records
Content-Type: application/json

{"name": "www", "ttl": "3600", "type": "A", "record": "1.2.3.4"}

MX example:

{"name": "example.com.", "ttl": "3600", "type": "MX", "priority": "10", "record": "mail.example.com."}

TXT / SPF example:

{"name": "example.com.", "ttl": "3600", "type": "TXT", "record": "v=spf1 include:_spf.example.com ~all"}

Update a record by line number​

PATCH /api/dns/example.com/records/12
Content-Type: application/json

{"content": "www 3600 IN A 5.6.7.8", "serial": "2025011501"}

The serial field prevents concurrent-edit conflicts — pass the serial you read when fetching the zone.

Delete a record​

DELETE /api/dns/example.com/records/12

Multi-line record (e.g. DKIM):

DELETE /api/dns/example.com/records/15
Content-Type: application/json

{"end_row_id": 18}

Reset zone to default template​

POST /api/dns/example.com/reset

Export zone file​

GET /api/dns/example.com/export

Traffic Stats (GoAccess)​

List domains with stats availability​

GET /api/stats

Get GoAccess report for a domain​

GET /api/stats/example.com
{
"domain": "example.com",
"available": true,
"html": "<!DOCTYPE html>..."
}

Stats are generated every 24 hours by the GoAccess daemon.


System Services​

List all services​

GET /api/services
{
"services": [
{"service": "nginx", "container_state": "running", "health_status": "healthy"},
{"service": "mysql", "container_state": "running", "health_status": "healthy"}
]
}

Get service status​

GET /api/services/nginx
{
"service": "nginx",
"container_state": "running",
"health_status": "healthy",
"available_actions": ["disable"]
}

Start or stop a service​

POST /api/services/nginx
Content-Type: application/json

{"action": "enable"} # enable | disable | restart

Webmail​

Get webmail info​

GET /api/webmail
{"is_running": true, "webmail_url": "https://webmail.example.com/"}

Generate auto-login token​

Creates a 30-second single-use token for automatic Roundcube login.

POST /api/webmail/[email protected]
{
"email": "[email protected]",
"token": "abc123...",
"autologin_url": "https://webmail.example.com/autologin.php?token=abc123...",
"webmail_url": "https://webmail.example.com/"
}

Website Builder​

Get HTML and CSS content​

GET /api/website-builder/example.com
{
"domain": "example.com",
"html": "<!DOCTYPE html>...",
"css": "* { box-sizing: border-box; }"
}

Save content​

PUT /api/website-builder/example.com
Content-Type: application/json

{
"html": "<!DOCTYPE html><html>...</html>",
"css": "body { margin: 0; }"
}

Create a new site​

POST /api/website-builder
Content-Type: application/json

{"domain_id": 1, "subdirectory": ""}
{"message": "Website created successfully on example.com", "site_name": "example.com"}

Remove a site (deletes files)​

DELETE /api/website-builder/sites/7

Detach a site (keeps files)​

POST /api/website-builder/sites/7/detach

Error Responses​

All endpoints return standard HTTP status codes:

CodeMeaning
200OK
201Created
202Accepted (async operation started)
400Bad request / missing required field
401Unauthorized (missing or invalid token)
403Forbidden (feature not enabled or domain not owned)
404Resource not found
409Conflict (e.g. serial mismatch, resource already exists)
500Internal server error
503Service unavailable
504Timeout

Error responses always include an error field:

{"error": "You do not own this domain"}