Every OwnPay plugin declares a set of capabilities in itsDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/own-pay/OwnPay-Documentation/llms.txt
Use this file to discover all available pages before exploring further.
manifest.json. Capabilities serve two related purposes: they document what the plugin does and which platform subsystems it interacts with, and they map to RBAC permission keys that are checked against the platform’s role-permission system before certain operations execute. Declaring capabilities accurately is both a security obligation and a requirement for marketplace review.
The Trust Model
OwnPay uses a full-trust plugin model similar to WordPress: plugins uploaded by an operator run with full application trust. Under this model, capabilities are declarative metadata and an intent contract. They document what your plugin does and drive UI presentation in the admin panel.Capabilities are not a runtime sandbox that restricts PHP execution. The
PluginSandbox enforces a narrower set of hard security rules — blocked PHP functions, path containment, and SQL table access policies — independently of capability declarations. Declaring "db_write" does not magically grant you write access; it tells the platform and marketplace reviewers that your plugin performs writes, which triggers the appropriate review.Declaring Capabilities
Declare capabilities in thecapabilities array in manifest.json:
capabilities() method must return the matching Capability enum cases. Both declarations must be consistent — the manifest drives discovery and database storage; the class method is used for runtime introspection.
Full Capability Reference
The following table documents every value in theOwnPay\Plugin\Capability enum (src/Plugin/Capability.php).
| Capability | JSON Value | Required Permission Keys | Scope and Intent |
|---|---|---|---|
Capability::GATEWAY | "gateway" | gateway.process, gateway.config | Payment gateway adapter. The entrypoint must also implement GatewayAdapterInterface. Hooks into the payment processing pipeline via GatewayBridge. |
Capability::THEME | "theme" | theme.render | Checkout theme. Authorises overriding Twig checkout template paths and injecting CSS/JS into checkout pages. |
Capability::ADDON | "addon" | (none — base platform access) | General-purpose extension. The baseline capability for any plugin that does not process payments or replace checkout templates. |
Capability::COMMUNICATION | "communication" | comm.send | SMS, email, or chat delivery. Authorises connecting to outbound messaging providers (Twilio, Vonage, SMTP, Telegram, etc.). |
Capability::ANALYTICS | "analytics" | analytics.read | Reporting and BI. Grants read access to transactional datasets for rendering custom analytics dashboards. |
Capability::WEBHOOK | "webhook" | (none) | Custom inbound webhook handler. Allows the plugin to register listeners under the dynamic gateway.webhook.{slug} hook. |
Capability::NOTIFICATION | "notification" | (none) | Push and system notifications. Grants authority to post visual alert panels to the admin control panel. |
Capability::EXPORT | "export" | (none) | Data export. Grants permission to produce CSV, PDF, or Excel output from reporting datasets. |
Capability::AUTHENTICATION | "authentication" | (none) | SSO and OAuth. Authorises implementing external identity provider (OAuth2, SAML, LDAP) authentication layers. |
Capability::STORAGE | "storage" | storage.read, storage.write | External file storage. Grants permission to integrate with block storage providers (S3, GCS, Cloudflare R2). |
Capability::CRON | "cron" | (none) | Scheduled background jobs. Required when declaring cron entries in manifest.json. The cron class must implement CronJobInterface. |
Capability::DASHBOARD | "dashboard" | (none) | Admin dashboard widgets. Authorises injecting HTML/JS panels into the dashboard via admin.dashboard.before and admin.dashboard.bottom hooks. |
Capability::DB_READ | "db_read" | (none) | Database read. Read-query permissions scoped exclusively to op_plugin_* prefixed tables. Queries to core op_* tables are blocked by PluginSandbox::validateSql(). |
Capability::DB_WRITE | "db_write" | (none) | Database write. Insert/update/delete permissions scoped exclusively to op_plugin_* prefixed tables. |
Capability::FILE_READ | "file_read" | (none) | Filesystem read. Sandboxed to the plugin’s own directory via PluginSandbox::validateFilePath(). |
Capability::FILE_WRITE | "file_write" | (none) | Filesystem write. Confined to the plugin’s storage/ subdirectory via PluginSandbox::storagePath(). |
Capability::HTTP_OUTBOUND | "http_outbound" | (none) | Outbound HTTP. Declares that the plugin makes curl requests to remote APIs. |
Capability::HOOKS | "hooks" | (none) | Event hook subscriptions. Declares that the plugin subscribes to EventManager action and filter hooks. |
Capability::CHECKOUT_UI | "checkout_ui" | (none) | Checkout UI injection. Grants permission to filter Twig context variables and inject UI elements into the checkout via checkout.render, checkout.head, checkout.footer. |
Capability-to-Permission Mapping
TheCapability::requiredPermissions() method returns the RBAC permission keys required for each capability. These keys are matched against the permissions array in manifest.json and the platform’s role-permission system (op_roles, op_role_permissions):
manifest.json:
Common Capability Combinations
Most plugins fall into one of these well-understood archetypes. Use the combination that matches your plugin’s actual behavior.- Payment Gateway
- Communication Addon
- Analytics Dashboard
- Data Export
- Background Sync
- Checkout Theme
GatewayAdapterInterface. PluginLoader auto-registers it with GatewayBridge after the boot phase.Checking Capabilities at Runtime
ThePluginManifest class provides methods for introspecting declared capabilities:
PluginSandbox class exposes the same check alongside its hard security enforcement methods:
Security-Relevant Capability Notes
db_read / db_write — SQL Isolation
When a plugin’s hook callback modifies a database query through the db.query.before filter, EventManager::applyFilter() automatically invokes PluginSandbox::validateSql() on the resulting SQL. This check rejects:
- DDL statements:
DROP,TRUNCATE,ALTER,CREATE TABLE,CREATE DATABASE,CREATE USER - Privilege statements:
GRANT,REVOKE - File operations:
LOAD_FILE,INTO OUTFILE,INTO DUMPFILE - Access to any
op_*table not prefixed withop_plugin_
RuntimeException that is re-thrown — unlike other hook errors which are swallowed, SQL sandbox violations halt the request immediately.
file_read / file_write — Path Containment
PluginSandbox::validateFilePath() uses realpath() to resolve the target path and verifies it begins with the plugin directory path followed by a directory separator. This prevents directory traversal attacks:
Blocked PHP Functions
Regardless of capabilities,PluginLoader token-scans every PHP file before loading it. The following direct function calls cause an immediate load failure:
| Blocked Function | Reason |
|---|---|
eval | Dynamic code evaluation |
exec() | Direct OS command execution |
shell_exec() | Shell command via backtick-equivalent |
system() | OS command with direct output |
passthru() | Raw OS command execution |
popen() | Process pipe opener |
proc_open() | Full process control |
pcntl_exec() | Process image replacement |
dl() | Dynamic extension loading |
assert() | Code evaluation via assertion |
create_function() | Runtime lambda code generation |
Only bare function invocations are blocked. Method calls (
$obj->system()), static calls (MyClass::exec()), and function declarations (function exec() {}) are not flagged by the token scanner.Principle of Least Privilege
Declare only the capabilities your plugin genuinely requires. This is both a security best practice and a marketplace submission requirement.Under-declare
Missing a required capability causes
PluginManifest::validate() to throw during load, or causes admin panel grouping to be incorrect.Over-declare
Unnecessary capabilities trigger additional security review, mislead operators about what the plugin does, and may block marketplace approval.
- Does your plugin call
curl? → Add"http_outbound". - Does your plugin read from an
op_plugin_*table? → Add"db_read". - Does your plugin write to an
op_plugin_*table? → Add"db_write". - Does your plugin register
addAction()oraddFilter()? → Add"hooks". - Does your plugin declare a
cronentry inmanifest.json? → Add"cron". - Does your plugin send SMS, email, or chat messages? → Add
"communication". - Does your plugin override checkout templates? → Use
"theme"and"checkout_ui", not"addon". - Does your plugin integrate with S3 or another block storage service? → Add
"storage".