{M} is the name field from module.json, for example PterodactylService.
Service module classes
Only
ModuleServiceActions and the three Actions\* classes are needed for a working module.
Everything else gates an optional feature.There used to be a
Modules\{M}\Services\{M}Service class for termination. It never resolved,
because the lookup produced names like PterodactylServiceService. Termination goes through
Actions\DeleteServerService via ServiceManagementService::executeModuleAction(). Ignore that
pattern if you see it in older code.Gateway module classes
Gateway key:
Str::lower(Str::before($moduleName, 'Gateway')), so AcmeGateway gives acme.
getGatewayName() must return it.
PaymentGatewayInterface
PaymentGatewayInterface
protected function getGatewayName(): string.Optional gateway interfaces
Optional gateway interfaces
getConfig() shape
getConfig() shape
handlePaymentSuccess() types
handlePaymentSuccess() types
$paymentData['type'] is one of market, renewal, invoice, upgrade, downgrade,
configurable_options_change, addon, balance, standalone.OAuth provider modules
Discovered byApp\Modules\OAuthProviderRegistry, which scans enabled modules whose name contains
Provider.
Core base classes and interfaces
Core events
All post-events. None can veto or change the action.
Core jobs that call modules
Middleware
Route files
module.json fields
permissions shape
gateway_settings (“Gateway & Service Settings”) and
addon_module_settings (“Addon Module Settings”).
Settings page definition
Returned fromsettingsDefinition(). Rendered by the shared admin/ModuleSettings page.
string
required
Heading shown on the page.
string
required
One line under the heading.
string
required
Where the form POSTs. Use
url(), not route().array
required
See field types.
array
Splits the form into tabs. Each entry takes
key, label and optional description.string
Adds a Test connection button to the header.
string
Overrides the button text.
string[]
Sidebar hints. Ones containing a URL get a copy button.
array
Sidebar panels. Take
title, description, status, status_tone and rows.module_name, display_name, logo, category, kind_label, back_url and back_label are
filled in from module.json by ModuleSettingsController. You don’t set them.Commands
make:payment-gateway still exists and works, but make:module --type=gateway supersedes it.Things that still need a core change
Everything else, including admin routes, permissions, OAuth registration and provider branding, is
declarable from the module itself.

