# How to Implement a Custom Payment Gateway in Magento 2: Complete Developer Guide

> Master implementing a custom payment gateway in Magento 2. Follow our developer guide to configure XML, build payment models, integrate frontend components, and handle webhook callbacks.

- Repository: [Alessandro Ronchi/mageres](https://github.com/aleron75/mageres)
- Tags: how-to-guide
- Published: 2026-02-24

---

**Implementing a custom payment gateway in Magento 2 requires creating a module with [`etc/config.xml`](https://github.com/aleron75/mageres/blob/main/etc/config.xml) configuration, a payment model extending `\Magento\Payment\Model\Method\AbstractMethod`, frontend Knockout.js components, and a CSRF-exempt webhook controller to handle gateway callbacks.**

Creating a custom payment gateway in Magento 2 involves architecting a module that bridges the platform's checkout flow with external payment processors. The **Mageres** repository maintains a curated index of Magento 2 resources, including the **Mage2Gen AI** code generator referenced at line 196 of the README that can scaffold complete payment modules from natural language descriptions. This guide walks through the actual implementation based on Magento 2 source architecture and the resource collection maintained by aleron75/mageres.

## Setting Up the Module Structure

Every payment gateway starts with standard module registration. In your `app/code/Vendor/CustomPay` directory, create the foundational files that declare the module to Magento's component registrar.

### Module Declaration

First, register the component in [`registration.php`](https://github.com/aleron75/mageres/blob/main/registration.php):

```php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Vendor_CustomPay',
    __DIR__
);

```

Then define the module metadata in [`etc/module.xml`](https://github.com/aleron75/mageres/blob/main/etc/module.xml):

```xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Vendor_CustomPay" setup_version="1.0.0"/>
</config>

```

## Configuring the Payment Method

Payment configuration in Magento 2 spans both system defaults and admin-editable fields. The [`etc/config.xml`](https://github.com/aleron75/mageres/blob/main/etc/config.xml) file establishes the initial state, while [`etc/adminhtml/system.xml`](https://github.com/aleron75/mageres/blob/main/etc/adminhtml/system.xml) exposes controls in the backend.

### Default Configuration in etc/config.xml

Define default values for your gateway in [`etc/config.xml`](https://github.com/aleron75/mageres/blob/main/etc/config.xml):

```xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Config/etc/config.xsd">
    <default>
        <payment>
            <vendor_custompay>
                <active>1</active>
                <title>My Custom Gateway</title>
                <model>Vendor\CustomPay\Model\Method</model>
                <order_status>pending</order_status>
                <allow_currency>USD,EUR</allow_currency>
            </vendor_custompay>
        </payment>
    </default>
    </config>
</config>

```

### Admin Configuration Fields

To expose settings in **Stores → Configuration → Sales → Payment Methods**, create [`etc/adminhtml/system.xml`](https://github.com/aleron75/mageres/blob/main/etc/adminhtml/system.xml):

```xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <section id="payment">
            <group id="vendor_custompay" translate="label" type="text" sortOrder="100" showInDefault="1"
                   showInWebsite="1" showInStore="1">
                <label>My Custom Gateway</label>
                <field id="active" translate="label" type="select" sortOrder="10" showInDefault="1"
                       showInWebsite="1" showInStore="1">
                    <label>Enabled</label>
                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                </field>
                <!-- Additional fields: API keys, endpoint URLs, etc. -->
            </group>
        </section>
    </system>
</config>

```

## Creating the Payment Model

The core logic resides in a class extending `\Magento\Payment\Model\Method\AbstractMethod` located in [`Model/Method.php`](https://github.com/aleron75/mageres/blob/main/Model/Method.php). This class must implement `\Magento\Payment\Model\MethodInterface` to handle transaction flows.

### Core Payment Methods

Your model must implement critical transaction methods including `authorize()`, `capture()`, and `refund()`:

```php
namespace Vendor\CustomPay\Model;

use Magento\Payment\Model\Method\AbstractMethod;

class Method extends AbstractMethod
{
    protected $_code = 'vendor_custompay';
    protected $_isInitializeNeeded = true;

    public function isAvailable(\Magento\Quote\Api\Data\QuoteInterface $quote = null)
    {
        // Add custom availability logic (e.g., country, total)
        return parent::isAvailable($quote);
    }

    public function authorize(\Magento\Payment\Model\InfoInterface $payment, $amount)
    {
        // Send request to external API, handle response
        // Throw \Magento\Framework\Exception\LocalizedException on failure
        return $this;
    }

    public function capture(\Magento\Payment\Model\InfoInterface $payment, $amount)
    {
        // Process capture transaction
        return $this;
    }
}

```

## Frontend Checkout Integration

Magento 2 uses Knockout.js for checkout UI components. You must provide templates and renderers to display your payment form or redirect button.

### Knockout.js Templates and Renderers

Create the HTML template in [`view/frontend/web/template/payment/form.html`](https://github.com/aleron75/mageres/blob/main/view/frontend/web/template/payment/form.html) to collect card data or display redirect instructions. Bind this template using a renderer in [`view/frontend/web/js/view/payment/method-renderer/custom-pay.js`](https://github.com/aleron75/mageres/blob/main/view/frontend/web/js/view/payment/method-renderer/custom-pay.js) that extends the default payment component logic.

## Handling Gateway Callbacks

External payment processors require webhook endpoints to update order statuses asynchronously. These controllers must handle POST requests securely without standard form key validation.

### CSRF-Exempt Controllers

Create a controller in [`Controller/Gateway/Callback.php`](https://github.com/aleron75/mageres/blob/main/Controller/Gateway/Callback.php) that implements `\Magento\Framework\App\ActionInterface`:

```php
namespace Vendor\CustomPay\Controller\Gateway;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;

class Callback extends Action
{
    public function __construct(Context $context) { 
        parent::__construct($context); 
    }

    public function execute()
    {
        // Verify signature, update order status
        // Respond with proper HTTP status
    }
}

```

Declare the route in [`etc/frontend/routes.xml`](https://github.com/aleron75/mageres/blob/main/etc/frontend/routes.xml) and mark the controller as CSRF-exempt if the external gateway cannot send a CSRF token.

## Testing and Deployment

Validate your implementation using Magento's testing frameworks before production deployment.

### Unit Testing

Place test classes under `Test/Unit/` and extend `\PHPUnit\Framework\TestCase`. Run `bin/magento dev:tests:run unit` to verify `authorize()` and `capture()` logic handle success and failure scenarios correctly.

### CLI Installation Commands

Enable the module using Magento's CLI:

```bash
php bin/magento module:enable Vendor_CustomPay
php bin/magento setup:upgrade
php bin/magento cache:clean

```

The gateway will now appear under **Stores → Configuration → Sales → Payment Methods**.

## Accelerating Development with Mage2Gen AI

According to the Mageres repository README at line 196, **Mage2Gen AI** can generate scaffold code for payment gateways from natural language prompts. This service produces [`module.xml`](https://github.com/aleron75/mageres/blob/main/module.xml), [`Model/Method.php`](https://github.com/aleron75/mageres/blob/main/Model/Method.php) stubs with `authorize()` and `capture()` methods, frontend UI components, and sample webhook controllers. Using this tool reduces boilerplate coding time, allowing developers to focus on API integration logic and security validation.

## Summary

- **Create module skeleton** with [`registration.php`](https://github.com/aleron75/mageres/blob/main/registration.php) and [`etc/module.xml`](https://github.com/aleron75/mageres/blob/main/etc/module.xml) to declare the component
- **Configure payment defaults** in [`etc/config.xml`](https://github.com/aleron75/mageres/blob/main/etc/config.xml) and admin fields in [`etc/adminhtml/system.xml`](https://github.com/aleron75/mageres/blob/main/etc/adminhtml/system.xml)
- **Implement `\Magento\Payment\Model\Method\AbstractMethod`** in [`Model/Method.php`](https://github.com/aleron75/mageres/blob/main/Model/Method.php) with `authorize()`, `capture()`, and `isAvailable()` methods
- **Build frontend components** in `view/frontend/web/` using Knockout.js templates and renderers
- **Handle asynchronous responses** via CSRF-exempt controllers in `Controller/` to process webhooks
- **Test thoroughly** using Magento's PHPUnit framework before running `setup:upgrade`

## Frequently Asked Questions

### What base class should I extend for a custom payment method?

Extend `\Magento\Payment\Model\Method\AbstractMethod` and implement required methods like `authorize()`, `capture()`, and `isAvailable()`. This base class provides the infrastructure for payment processing while allowing you to define gateway-specific logic for API communication.

### How do I restrict my payment gateway to specific countries?

Override the `isAvailable()` method in your [`Model/Method.php`](https://github.com/aleron75/mageres/blob/main/Model/Method.php) file to check the quote's billing country against your allowed list before returning `parent::isAvailable($quote)`. Alternatively, configure this via [`etc/config.xml`](https://github.com/aleron75/mageres/blob/main/etc/config.xml) using standard Magento fields like `allowspecific` and `specificcountry`.

### Where should webhook controllers be placed in the module structure?

Place webhook controllers in the `Controller/` directory (e.g., [`Controller/Gateway/Callback.php`](https://github.com/aleron75/mageres/blob/main/Controller/Gateway/Callback.php)) and declare routes in [`etc/frontend/routes.xml`](https://github.com/aleron75/mageres/blob/main/etc/frontend/routes.xml). Ensure the action implements proper signature verification for external POST requests that cannot include Magento form keys.

### Can I generate boilerplate code automatically instead of writing it manually?

Yes. The Mageres repository references **Mage2Gen AI**, which generates complete payment module scaffolding including configuration files, payment models, and frontend components from natural language descriptions. This significantly reduces initial development time when you implement a custom payment gateway in Magento 2.