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

Implementing a custom payment gateway in Magento 2 requires creating a module with 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:

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

Then define the module metadata in etc/module.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 file establishes the initial state, while 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:

<?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:

<?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. 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():

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 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 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 that implements \Magento\Framework\App\ActionInterface:

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 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:

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, 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 and etc/module.xml to declare the component
  • Configure payment defaults in etc/config.xml and admin fields in etc/adminhtml/system.xml
  • Implement \Magento\Payment\Model\Method\AbstractMethod in 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 file to check the quote's billing country against your allowed list before returning parent::isAvailable($quote). Alternatively, configure this via 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) and declare routes in 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →