Everyone

How Provisioning Works

Provisioning is Commerce's automated system for creating and managing hosting accounts on linked servers when clients purchase hosting products.

Last updated 1776211200

Overview

When a client pays for a hosting product, Commerce automatically creates a hosting account on the target server — no manual intervention required. This is provisioning.

Commerce communicates with hosting panels through provisioning modules: pluggable PHP classes, each implementing a standard interface. The registry auto-discovers every module in app/Provisioning/Modules/ at boot. Adding support for a new hosting provider requires dropping a single class file — no core code changes, no migrations, no service provider registration.

Architecture

Order Paid
    └─▶ CreateHostingAccountJob
            └─▶ ProvisioningModuleRegistry
                    └─▶ ProvisioningModule (e.g. OpteriusPanelModule)
                            └─▶ Panel API
Component Role
ProvisioningModuleRegistry Singleton. Scans app/Provisioning/Modules/, loads all modules.
ProvisioningModule interface Contract every module must implement.
Server model Stores module type (servers.type), credentials (JSON), and max_accounts.
ServerGroup model Pool of servers for a product type. Selects best server on order.
provisioning_log table Records every action — success or failure — with full request/response payloads.

How a Module Is Selected

Each Server record has a type field that matches a module's moduleId(). When a job runs, Commerce calls ProvisioningModuleRegistry::resolve($server->type) to get the right module instance, injecting the server's credentials automatically.

Built-In Module: Opterius Panel

The OpteriusPanelModule (type = opterius) is the first-class module for Opterius Panel servers. Every API request is authenticated with HMAC-SHA256 — the job sends X-Timestamp (Unix timestamp) and X-Signature (HMAC of timestamp + JSON body, keyed by api_token). This means the Panel never needs to trust a plain bearer token — each request is time-bound and body-signed.

Adding a Custom Module

  1. Create a class in app/Provisioning/Modules/MyProviderModule.php.
  2. Implement ProvisioningModule — all required methods are defined there.
  3. Return ProvisioningResult::success() or ProvisioningResult::failure() from each action method.
  4. Deploy. Commerce picks it up automatically on next request.

No restart required. The registry resolves modules at runtime, so a deploy + opcache clear is sufficient.

Credential Storage

Credentials are stored in servers.credentials as a JSON blob cast to an array. Secret fields (marked secret: true in moduleFields()) are:

  • Masked on the edit form (shown as empty password inputs).
  • Never overwritten if the field is submitted blank — Commerce keeps the existing encrypted value.
  • Decrypted in memory only when the module needs them.

What Happens When Provisioning Fails

Jobs retry 3 times with a 60-second backoff. After all retries are exhausted, the failure is written to provisioning_log with the full API error response. The service remains in pending status. An admin notification is triggered.

See Provisioning Log to diagnose failures and Provisioning Troubleshooting for common fixes.

Related