Skip to content

Replication

MySQL primary/replica configuration across multiple panel-managed servers.

All endpoints below are mounted under /api. Authentication: Authorization: Bearer <token> unless noted as public.

Endpoint count: 10

Endpoints

Method Path Handler Guards
DELETE /api/replication-servers/:id deleteReplicationServer RequirePermission(db, "plugins_management")
PUT /api/replication-servers/:id updateReplicationServer RequirePermission(db, "plugins_management")
DELETE /api/replication-servers/:id/action-log clearReplicationActionLog RequirePermission(db, "plugins_management")
GET /api/replication-servers/:id/action-log getReplicationActionLog RequirePermission(db, "plugins_management")
POST /api/replication-servers/:id/action-log/:action_id/retry retryReplicationAction RequirePermission(db, "plugins_management")
GET /api/replication-servers/:id/categories getReplicationCategories RequirePermission(db, "plugins_management")
PUT /api/replication-servers/:id/categories updateReplicationCategories RequirePermission(db, "plugins_management")
PATCH /api/replication-servers/:id/categories/:category updateReplicationCategory RequirePermission(db, "plugins_management")
POST /api/replication-servers/:id/test testReplicationServer RequirePermission(db, "plugins_management")
POST /api/replication-servers/:id/toggle toggleReplicationServer RequirePermission(db, "plugins_management")

Source

Handlers for this section live in api/routes/handlers_*.go in the StarkOne source. Each handler binds its request body with gin.ShouldBindJSON(&req) and responds with the standard envelope:

{ "data": { ... } }

On error:

{ "error": { "code": "string", "message": "string" } }

Reference

DELETE /api/replication-servers/:id

Deletes a replication server, but only if no website replications still reference it.

Guards: RequirePermission(db, "plugins_management")

Path parameters

Name Type Description
id string The replication server ID.

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
400 - One or more website replications still use this server (response carries a message like Cannot delete: N replications use this server; no code field).

Side effects

  • Deletes the matching row from the replication_servers table.

Example

curl -X DELETE https://panel.example.com:2087/api/replication-servers/3 \
  -H "Authorization: Bearer $TOKEN"

PUT /api/replication-servers/:id

Updates the editable fields of a replication server; only the non-empty fields supplied in the body are changed.

Guards: RequirePermission(db, "plugins_management")

Path parameters

Name Type Description
id string The replication server ID.

Request body

{
  "name": "string (optional)",
  "host": "string (optional)",
  "port": "int (optional)",
  "api_key": "string (optional)"
}
Field Type Required Description
name string no New display name. Applied only when non-empty.
host string no New hostname/IP. Applied only when non-empty.
port int no New port. Applied only when greater than 0.
api_key string no New API key for authenticating to the remote panel. Applied only when non-empty.

No field carries binding:"required". However, at least one effective field must be provided or the request is rejected.

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
400 - Request body could not be parsed (message holds the bind error).
400 - No usable fields supplied (message: No fields to update).
500 - Database update failed.

Side effects

  • Updates the matching row in replication_servers, including updated_at = datetime('now').

Example

curl -X PUT https://panel.example.com:2087/api/replication-servers/3 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"host": "203.0.113.20", "port": 2087}'

DELETE /api/replication-servers/:id/action-log

Clears action-log entries for a server; by default only completed rows (success, or failed with retry_count >= 3), or all rows when ?all=true.

Guards: RequirePermission(db, "plugins_management")

Path parameters

Name Type Description
id string The replication server ID.

Query parameters

Name Type Optional Description
all string yes When set to true, deletes every action-log row for the server. Otherwise only success rows and exhausted failures (retry_count >= 3) are removed.

Response - 200 OK

{ "data": { "success": true, "deleted": 12 } }

deleted is the number of rows removed.

Errors

Status Code Meaning
500 - Database delete failed.

Side effects

  • Deletes rows from replication_action_log for the given server.

Example

curl -X DELETE "https://panel.example.com:2087/api/replication-servers/3/action-log?all=true" \
  -H "Authorization: Bearer $TOKEN"

GET /api/replication-servers/:id/action-log

Returns recent forwarded actions for a server, newest first, with optional filtering by category and status.

Guards: RequirePermission(db, "plugins_management")

Path parameters

Name Type Description
id string The replication server ID.

Query parameters

Name Type Optional Description
limit int yes Max rows to return. Defaults to 50; only honored when in the range 1-500, otherwise the default applies.
category string yes Filter to a single replication category.
status string yes Filter by action status (e.g. success, failed, pending).

Response - 200 OK

{
  "data": [
    {
      "id": 101,
      "server_id": 3,
      "category": "dns",
      "method": "POST",
      "endpoint": "/dns/zones",
      "request_body": "{...}",
      "status": "failed",
      "response_code": 500,
      "error_message": "connection refused",
      "retry_count": 1,
      "created_at": "2026-06-17 10:00:00",
      "completed_at": ""
    }
  ]
}

On a query error the handler returns 200 OK with an empty data array rather than an error status.

Example

curl "https://panel.example.com:2087/api/replication-servers/3/action-log?status=failed&limit=100" \
  -H "Authorization: Bearer $TOKEN"

POST /api/replication-servers/:id/action-log/:action_id/retry

Re-attempts a single action-log entry by re-forwarding the stored request to the remote server and updating the log row with the outcome.

Guards: RequirePermission(db, "plugins_management")

Path parameters

Name Type Description
id string The replication server ID.
action_id string The action-log entry ID to retry (must belong to this server).

Response - 200 OK

On success:

{ "data": { "success": true, "response_code": 200 } }

On a failed retry (still 200 OK):

{ "data": { "success": false, "response_code": 500, "error": "connection refused" } }

Errors

Status Code Meaning
404 - No matching action-log entry for this server (message: Action not found).

Side effects

  • Sends the stored HTTP request (method + endpoint + body) to the remote replication server via doForwardRequest.
  • Updates the replication_action_log row: on success sets status = 'success', clears error_message, sets response_code and completed_at; on failure sets status = 'failed', stores response_code and error_message. retry_count is incremented either way.

Example

curl -X POST https://panel.example.com:2087/api/replication-servers/3/action-log/101/retry \
  -H "Authorization: Bearer $TOKEN"

GET /api/replication-servers/:id/categories

Returns the full list of known replication categories for a server, each marked enabled or disabled.

Guards: RequirePermission(db, "plugins_management")

Path parameters

Name Type Description
id string The replication server ID.

Response - 200 OK

Every known category is returned (categories without a stored row default to enabled: false). The known categories are: websites, dns, ssl, aliases, databases, firewall, users, ssh_keys, crontab, php, settings, services, ftp, waf, varnish, rate_limit, plugins, limits, nginx_acl, performance, webapp_backups.

{
  "data": [
    { "category": "websites", "enabled": true },
    { "category": "dns", "enabled": false }
  ]
}

Errors

Status Code Meaning
404 - Server not found (message: Server not found).

Example

curl https://panel.example.com:2087/api/replication-servers/3/categories \
  -H "Authorization: Bearer $TOKEN"

PUT /api/replication-servers/:id/categories

Performs a bulk upsert of category enabled/disabled flags for a server; unknown category keys are silently skipped.

Guards: RequirePermission(db, "plugins_management")

Path parameters

Name Type Description
id string The replication server ID.

Request body

{
  "categories": { "websites": true, "dns": false }
}
Field Type Required Description
categories object (map of string→bool) no (no binding tag) Map of category name to enabled flag. Keys not in the known-category list are ignored.

Response - 200 OK

{ "data": { "success": true, "updated": 2 } }

updated counts the recognized categories that were upserted.

Errors

Status Code Meaning
400 - Request body could not be parsed (message holds the bind error).
404 - Server not found (message: Server not found).
500 - Transaction start, upsert, or commit failed.

Side effects

  • Upserts rows in replication_categories inside a transaction.
  • If the websites key is present, spawns a background request to lock/unlock website creation on the remote server (POST /api/settings/website-creation-lock).

Example

curl -X PUT https://panel.example.com:2087/api/replication-servers/3/categories \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"categories": {"websites": true, "dns": false}}'

PATCH /api/replication-servers/:id/categories/:category

Toggles a single replication category on or off for a server.

Guards: RequirePermission(db, "plugins_management")

Path parameters

Name Type Description
id string The replication server ID.
category string The category to toggle. Must be one of the known categories.

Request body

{ "enabled": true }
Field Type Required Description
enabled bool no (no binding tag) Whether the category should be enabled.

Response - 200 OK

{ "data": { "success": true, "category": "websites", "enabled": true } }

Errors

Status Code Meaning
400 - Unknown category (message: Unknown category).
400 - Request body could not be parsed (message holds the bind error).
404 - Server not found (message: Server not found).
500 - Database upsert failed.

Side effects

  • Upserts a single row in replication_categories.
  • When the toggled category is websites, spawns a background request to lock/unlock website creation on the remote server.

Example

curl -X PATCH https://panel.example.com:2087/api/replication-servers/3/categories/websites \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled": true}'

POST /api/replication-servers/:id/test

Tests connectivity to a replication server by calling its /api/version endpoint, then stores the result on the server record.

Guards: RequirePermission(db, "plugins_management")

Path parameters

Name Type Description
id string The replication server ID.

Response - 200 OK

{ "data": { "status": "active", "message": "" } }

status is active when the remote returns HTTP 200, otherwise error with message describing the failure (transport error or Status <code>).

Errors

Status Code Meaning
404 - Server not found (message: Server not found).

Side effects

  • Makes an outbound HTTPS GET to https://<host>:<port>/api/version (TLS verification disabled, 10s timeout), sending the stored API key as a bearer token when present.
  • Updates the server row's status and last_check.

Example

curl -X POST https://panel.example.com:2087/api/replication-servers/3/test \
  -H "Authorization: Bearer $TOKEN"

POST /api/replication-servers/:id/toggle

Enables or disables a replication server (sets its status) without deleting it.

Guards: RequirePermission(db, "plugins_management")

Path parameters

Name Type Description
id string The replication server ID.

Request body

{ "enabled": true }
Field Type Required Description
enabled bool no (no binding tag) true sets status to active; false sets status to disabled.

Response - 200 OK

{ "data": { "success": true, "status": "active" } }

Errors

Status Code Meaning
400 - Request body could not be parsed (message holds the bind error).
500 - Database update failed.

Side effects

  • Updates the server row's status and updated_at.

Example

curl -X POST https://panel.example.com:2087/api/replication-servers/3/toggle \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled": false}'