Skip to content

System API Documentation

System health monitoring and diagnostics endpoints for infrastructure components.

Check System Health

GET /api/v1/system-health-check

API Usage Notes

  • Authentication required: Admin API Key (via Bearer token or query parameter)
  • Legacy endpoint access via /api.php is also supported

Request Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: system.health.check (only for legacy endpoint)
AdminAPIKeyStringNoAdmin API key for authentication (alternative to Bearer token)

Authentication Methods:

This endpoint supports two authentication methods:

  1. Bearer Token (Recommended): Include the Admin API Key in the Authorization header:

    Authorization: Bearer YOUR_ADMIN_API_KEY
  2. Query Parameter: Pass the Admin API Key as a query parameter:

    ?adminapikey=YOUR_ADMIN_API_KEY
bash
curl -X GET https://example.com/api/v1/system-health-check \
  -H "Authorization: Bearer YOUR_ADMIN_API_KEY"
bash
curl -X GET "https://example.com/api/v1/system-health-check?adminapikey=YOUR_ADMIN_API_KEY"
bash
curl -X GET "https://example.com/api.php?Command=system.health.check&adminapikey=YOUR_ADMIN_API_KEY"
json
{
  "Checks": {
    "MySQL": "OK",
    "ClickHouse": "OK",
    "Elasticsearch": "OK",
    "RabbitMQ": "OK",
    "Redis": "OK",
    "Session": "OK",
    "SystemContainer": "OK",
    "Vector": "OK",
    "WebsiteEventRouting": "OK",
    "Haproxy": "OK",
    "Cron": "OK",
    "Supervisor": "OK",
    "SendEngine": "OK",
    "AdminFrontend": "OK",
    "UserFrontend": "OK",
    "FilePermissions": "OK"
  }
}
json
{
  "Checks": {
    "MySQL": "OK",
    "ClickHouse": "OK",
    "Elasticsearch": "Connection refused",
    "RabbitMQ": "OK",
    "Redis": "[111] Connection refused",
    "Session": "OK",
    "SystemContainer": "OK",
    "Vector": "Timeout after 3 seconds",
    "WebsiteEventRouting": "HAProxy did not route /hello/message to backend_vector (HTTP 503; \"X-Server: oempro_vector\" response header missing). Check that backend_vector has an available server.",
    "Haproxy": "OK",
    "Cron": "App container cron not executing (last run: 120 seconds ago)",
    "Supervisor": "# campaign_delivery_worker: STOPPED # journey_worker: FATAL ",
    "SendEngine": "No send engine containers running",
    "AdminFrontend": "OK",
    "UserFrontend": "Backend user login form action is not found",
    "FilePermissions": "logs/campaign_delivery.log: expected 0777, 0666 or 0644, found 0640"
  }
}
json
{
  "Errors": [
    {
      "Code": 1,
      "Message": "Authentication failed. Invalid admin API key."
    }
  ]
}
txt
0: Success - All health checks passed
1: Authentication failed. Invalid admin API key.

HTTP Status Codes:
200: All health checks passed
403: Authentication failed
503: One or more health checks failed (see Checks object for details)

Health Check Components:

The endpoint performs comprehensive health checks on the following components:

  • MySQL: Database connectivity and admin user existence
  • ClickHouse: Analytics database connectivity
  • Elasticsearch: Search engine connectivity and indices
  • RabbitMQ: Message queue connectivity
  • Redis: Cache server connectivity
  • Session: PHP session functionality
  • SystemContainer: Laravel backend container health (/system/ping)
  • Vector: Log aggregation service health (probed directly)
  • WebsiteEventRouting New in v5.9.3: The full load-balancer → Vector path used by the public website-event tracker
  • Haproxy: Load balancer connectivity
  • Cron: App and system container cron job execution (heartbeat checks)
  • Supervisor: Process manager status for all managed processes
  • SendEngine: Send engine container discovery and supervisor process status
  • AdminFrontend: Admin login page accessibility and form validation
  • UserFrontend: User login page accessibility and form validation
  • FilePermissions: Directory and log file permissions (expects 0777 for directories, 0777/0666/0644 for log files)

Response Details:

  • Each check returns "OK" if successful
  • Failed checks return detailed error messages explaining the failure
  • HTTP status code 200 indicates all checks passed
  • HTTP status code 503 indicates one or more checks failed (response still includes all check results)
  • The Cron check monitors heartbeat files updated every minute; considers cron failed if > 90 seconds since last update
  • The Supervisor check reports processes not in RUNNING state with format: # process_name: STATE
  • The SendEngine check discovers containers dynamically using Docker Compose project prefix detection

The WebsiteEventRouting check

New in v5.9.3

The Vector check talks to the Vector container directly, so it cannot see a broken load-balancer route. WebsiteEventRouting exercises the routed path instead — the same path the public website-event tracker uses — so that failure mode is actually detected. Both checks are kept, so a genuine Vector outage stays distinguishable from broken routing.

This exists because of a real, long-lived outage: a startup DNS race left the Vector backend with no available server for roughly four weeks. The load balancer resolved the container name once at boot, failed while the container was still starting, and permanently disabled the server. Vector itself stayed healthy the whole time, so the health check reported OK while the public website-event endpoint returned HTTP 503 to every visitor.

How it probes:

  • It issues a GET to the website-event path through the load balancer. GET is deliberate — Vector's HTTP source only accepts POST, so a GET is rejected before ingestion. A synthetic POST would be forwarded downstream and inject a junk website event on every health-check tick.
  • It is also deliberately not an OPTIONS request: OPTIONS on the website-event paths is answered by a static backend that never touches Vector, so an OPTIONS probe would have stayed green throughout the outage described above.
  • The assertion is the presence of the X-Server: oempro_vector response header, which only the Vector backend adds. The load balancer's internally generated "no server available" 503 is produced before those backend response rules run and therefore carries no such header. Matching the header rather than the status code proves the response really came from Vector through the intended route.

On failure the check reports the observed HTTP status and states that the X-Server: oempro_vector header was missing, pointing the operator at the Vector backend's server availability.

Process PowerMTA Log File

POST /api/v1/process_pmta_log_file

API Usage Notes

  • Authentication required: Admin API Key (via Bearer token)
  • Rate limit: 100 requests per 60 seconds
  • This endpoint is designed for PowerMTA integration to process email delivery logs
  • Accepts batch processing of email events (delivery, bounce, etc.)
  • Legacy endpoint access via /api.php is also supported

Request Body Parameters:

ParameterTypeRequiredDescription
AdminAPIKeyStringYesAdmin API key for authentication (via Bearer token)
LogDataArrayYesArray of PowerMTA log entries (JSON format in POST body)

PowerMTA Log Entry Format:

Each log entry in the array should contain PowerMTA event data following the PowerMTA log format specification.

bash
curl -X POST https://example.com/api/v1/process_pmta_log_file \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ADMIN_API_KEY" \
  -d '[
    {
      "type": "delivery",
      "timeLogged": "2025-01-15T10:30:00Z",
      "recipient": "user@example.com",
      "messageId": "550e8400-e29b-41d4-a716-446655440000"
    },
    {
      "type": "bounce",
      "timeLogged": "2025-01-15T10:31:00Z",
      "recipient": "invalid@example.com",
      "bounceType": "hard"
    }
  ]'
json
{
  "Success": true,
  "ProcessedCount": 2,
  "ErrorCount": 0
}
json
{
  "Errors": [
    {
      "Code": 1,
      "Message": "Invalid AdminAPIKey"
    }
  ]
}
json
{
  "Errors": [
    {
      "Code": 2,
      "Message": "Invalid or empty log data"
    }
  ]
}
txt
200: Success - Log data processed successfully
400: Bad Request - Invalid or empty log data
401: Unauthorized - Invalid Admin API Key
429: Too many requests - Rate limit exceeded
txt
1: Invalid AdminAPIKey
2: Invalid or empty log data

Processing Behavior:

  • Accepts both JSON and form-encoded POST data
  • Processes events in batch for improved performance
  • Returns processing results with success/error counts
  • Failed events within a batch do not cause the entire batch to fail

Get System Settings

GET /api/v1/system-settings

API Usage Notes

  • Authentication required: Admin API Key (or logged-in admin session)
  • Legacy endpoint access via /api.php is also supported

Returns a unified snapshot of every Octeth configuration value the running instance can see. Settings are grouped by source so callers can drill into a specific layer without merging four separate views themselves.

The endpoint surfaces four sources:

  1. ConfigFiles — every *.php file under config/global/ (each returns an array). The app.php file is intentionally skipped because it declares the SystemConfig class and has side effects; its values are already represented in EnvSettings.octeth and DefinedConstants.
  2. EnvSettingsSystemConfig::$Config, populated from the six .oempro_*_env files: octeth, mysql, redis, rabbitmq, clickhouse, supervisor.
  3. RuntimeOptions — every row in the oempro_options table (the runtime-editable options used by OemproOptions::get()/set()). JSON-encoded values are decoded automatically when they are arrays.
  4. DefinedConstantsget_defined_constants(true)['user']: every constant registered by ConfigLoader plus library define() calls.

Sensitive value redaction: any key whose name contains a known secret substring (case-insensitive: PASSWORD, PASSWD, _PASS, SECRET, SALT, TOKEN, API_KEY, APIKEY, CLIENT_SECRET, ENCRYPTION_KEY, HMAC, ERLANG_COOKIE, LICENSE_KEY, AUTH_CODE, BUGSNAG_API, SENTRY_API, PRIVATE_KEY, WEBHOOK_SECRET) has its value replaced with the literal string "***REDACTED***". The key itself remains visible. Empty values pass through untouched so callers can distinguish "configured but blank" from "configured with a value, redacted".

Request Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: system.getsettings (only for legacy endpoint)
AdminAPIKeyStringNoAdmin API key for authentication (alternative to logged-in admin session). Sent as adminapikey query parameter.
SectionStringNoRestrict the response to a single source. Possible values: ConfigFiles, EnvSettings, RuntimeOptions, DefinedConstants. If omitted, all four sections are returned.
bash
curl -X GET "https://example.com/api/v1/system-settings?adminapikey=YOUR_ADMIN_API_KEY"
bash
curl -X GET "https://example.com/api.php?Command=System.GetSettings&adminapikey=YOUR_ADMIN_API_KEY"
bash
curl -X GET "https://example.com/api/v1/system-settings?Section=EnvSettings&adminapikey=YOUR_ADMIN_API_KEY"
json
{
  "Success": true,
  "Settings": {
    "ConfigFiles": {
      "email_delivery": { "EMAIL_DELIVERY_BATCH_SIZE": 100 },
      "sms": { "SMS_GATEWAY_TIMEOUT": 30 }
    },
    "EnvSettings": {
      "octeth": {
        "APP_URL": "https://example.com/",
        "PRODUCT_VERSION": "5.9.1",
        "MYSQL_PASSWORD": "***REDACTED***",
        "LICENSE_KEY": "***REDACTED***",
        "OEMPRO_PASSWORD_SALT": "***REDACTED***"
      },
      "mysql":      { "MYSQL_HOST": "oempro_mysql", "MYSQL_PASSWORD": "***REDACTED***" },
      "redis":      { "REDIS_HOST": "oempro_redis" },
      "rabbitmq":   { "RABBITMQ_DEFAULT_USER": "oempro", "RABBITMQ_DEFAULT_PASS": "***REDACTED***" },
      "clickhouse": { "CLICKHOUSE_HOST": "oempro_clickhouse" },
      "supervisor": { "SUPERVISOR_USERNAME": "admin" }
    },
    "RuntimeOptions": {
      "FailedWebhookHandler": "email",
      "DisableUserPasswordReset": ""
    },
    "DefinedConstants": {
      "APP_PATH": "/var/www/html",
      "CHARSET": "utf-8",
      "OEMPRO_DEBUG": true,
      "PRODUCT_VERSION": "5.9.1",
      "ADMIN_API_KEY": "***REDACTED***"
    }
  }
}
json
{
  "Success": false,
  "ErrorCode": 1,
  "ErrorMessage": "Invalid Section. Allowed: ConfigFiles, EnvSettings, RuntimeOptions, DefinedConstants"
}
txt
1: Invalid Section value (must be one of ConfigFiles, EnvSettings, RuntimeOptions, DefinedConstants)
99998: Authentication required - missing or invalid admin credentials

Use cases:

  • Diagnosing configuration drift between environments
  • Support escalations where the operator needs to share a redacted config snapshot
  • Verifying that a setting (env var, runtime option, or constant) is actually present and reaching the application
  • Auditing which secrets are configured without exposing their values

Any questions? Contact us.