Overview
Payment gateways are implemented as plugins that hook into two core filters: payment.charge (initiate) and payment.complete (verify and complete).
Architecture
Core Checkout --payment.charge--> Gateway Plugin (redirects to provider)
|
Provider redirects back / sends IPN webhook
|
v
Core Completion <--payment.complete-- Gateway Plugin (verifies & delegates)
Key principle: Core never references gateway plugins by name. Plugins self-register via the registry and hook into filters.
Directory Structure
plugins/my-payment-gateway/
├── plugin.json
├── README.md
├── config/
│ └── my-payment-gateway.php
├── routes/
│ ├── web.php # Auth-protected (checkout, admin)
│ └── api.php # Public (IPN/callback — no CSRF)
├── src/
│ ├── MyPaymentGatewayPlugin.php # Entry class
│ ├── MyGateway.php # Gateway logic
│ └── Http/
│ ├── Controllers/
│ │ ├── MyCheckoutController.php # Optional: hosted checkout page
│ │ ├── MyIpnController.php # Webhook receiver
│ │ └── MyAdminController.php # Admin settings
│ └── ...
├── views/
│ ├── pay.blade.php # Optional: checkout view
│ └── admin/
│ └── settings.blade.php # Admin settings view
└── database/
└── migrations/ # Optional: custom tables
Step 1: plugin.json
{
"name": "My Payment Gateway",
"slug": "my-payment-gateway",
"version": "1.0.0",
"entry": {
"file": "src/MyPaymentGatewayPlugin.php",
"class": "MyPaymentGateway\\MyPaymentGatewayPlugin"
},
"autoload": {
"psr-4": {
"MyPaymentGateway\\": "src/"
}
},
"requires": {
"framework": ">=1.0",
"php": ">=8.3"
},
"provides": ["payment.charge"],
"capabilities": ["outbound-https"],
"xilancerMetaData": {
"plugin_type": "external"
}
}
Last updated: September 2026
Still stuck?
Our support team is ready to help you get set up.

