How to Create a Payment Method in Magento 2
How to Create a Payment Method in Magento 2

How to Create a Payment Method in Magento 2

Published March 27, 2018 in Development
How to Build a Theme in Magento 2
March 6, 2018
Impact on Ad Rank and SERP’ real estate
May 11, 2018

Sometimes you might need more than the standard out-of-the-box payment method. Perhaps you have an agreement with a credit card processor and a solution for their platform is not available. Maybe you need to interject specific logic into the checkout flow to support an ERP. By building a custom payment method, you will be able to customize the fields the user will interact with on checkout and highly customize the API logic used to implement the payment method.

As an example, we’ll look at a scenario where a credit card processor doesn’t have a solution available for Magento 2. So we’ll examine how to add a credit card based payment method to Magento 2. We’ll examine the backend and frontend changes required to make the payment method work and where we can rely on native Magento logic. (Unless otherwise specified, all the following code examples and file paths will be relative to a new Magento module named ClassyLlama_LlamaCoin. For more detailed examples of the code here, you can refer to this GitHub.)

Foundation of a New Payment Method


First, in our new module we’ll need to add configuration settings for our payment method. For a custom payment method, you will likely have many additional configuration settings, but here we’re only going to add a few very basic settings. We will need an “enabled” setting, a title to display for our payment method, and a setting for which credit card types we will accept. These will be added in etc/adminhtml/system.xml. These fields, active, title, and cctypes, are used by the core classes we’re extending so make sure to match the field ids exactly. Additionally, it’s important to make sure these fields are added in the payment config namespace as Magento references this namespace when loading configuration fields.

Now we can define default values for the configuration settings we created. Create a new file in the etc folder named config.xml and define your values. There’s an additional field that has been added that we didn’t define in the system.xml file: the field model. This field defines the payment method model for our payment method.

Payment Model

Since the config.xml file tells Magento where to find our payment model class, we want to make sure this class is created: Model\LlamaCoin. This class is where the main logic that processes the payment information is found. The core Magento class defines several methods that we will want to implement in our class: authorize and capture. (There are several other methods defined, like void, but we won’t be implementing them in this example.) Your payment model must extend \Magento\Payment\Model\Method\AbstractMethod; if you’re creating a credit card method, though, you’ll probably want to extend \Magento\Payment\Model\Method\Cc, which provides helpful logic in the validate method. We’ll come back to this model and fill it in later.

After creating the system.xml and config.xml files and defining the base class for our payment method, we can now see our configuration settings in the admin. (Found at Stores > Configuration > Sales > Payment Methods)

Accessing the Configuration Data

On the frontend, we’ll need to give the checkout interface access to our payment method’s configuration fields. To provide this information, we must define a PHP provider class. Magento will use this provider class to store all the checkout-related configuration in the window.checkoutConfig Javascript object. The provider we create will need to implement the \Magento\Checkout\Model\ConfigProviderInterface interface and use the getConfig method to return the data we configured. However, Magento has built a generic class, \Magento\Payment\Model\CcGenericConfigProvider, that implements this required interface and additionally goes through all the available payment methods and gathers all the configuration fields we’ll need. This means we can simply inject our payment method into this CcGenericConfigProvider and it will load our data to the window.checkoutConfig object. Create a new file etc/frontend/di.xml and add our payment method code as an argument.

We have the foundation of our custom payment method in place, and the frontend will be able to access our data, so now we can display the payment method on the frontend.

Displaying the New Payment During Checkout

We’re adding a payment method that will utilize credit cards to checkout. Since Magento natively has several payment methods with credit card templates, we can utilize several core templates to render our payment method.


There are two important JS files to add: the payment method renderer and the component that registers the renderer. The contents of the component file, view/frontend/web/js/view/payment/llamacoin.js, are rather simple and only serve to add the renderer:

The file path of the renderer file is view/frontend/web/js/view/payment/method-renderer/. This file handles the frontend logic specific to the new payment method: validation on the form fields and accessor methods for the Knockout template data. In its simplest form, the renderer only needs to include the path to the Knockout template, and this renderer can depend on Magento_Checkout/js/view/payment/default. Since our payment method uses credit card fields, we can extend Magento_Payment/js/view/payment/cc-form. This base JavaScript file (and its associated Knockout template, cc-form.html) provide a form that contains the basic fields and validation for the credit card fields (number, date, type, year, and csv). By depending on these forms, you can leverage a great deal of basic functionality and then customize it to your needs.


The JS renderer uses Knockout to render the uiComponent. The native templates used in this rendering process are found in the Magento_Payment/view/frontend/web/template/payment/ folder. But we’ll need to add one template, effectively a wrapper around our form, to contain a radio button, title, and billing address for our payment method. Create the new template at /view/frontend/web/template/payment/llamacoin.html. In this template, we’re using Knockout to render the native credit card form and a place to display the address. (This new template is heavily based off the native free.html template in the location referenced above.)

If you need to customize the fields on the credit card form, simply copy forward the native cc-form.html file to your module, update the reference in your JavaScript renderer file, and make your changes to the new template.


Finally, we need to tell Magento where to include these JavaScript files. Create a new layout file view/frontend/layout/checkout_index_index.xml. (Sections of the file below have been left out. For the entire file, view checkout_index_index.xml in the GitHub example I’ve created.) In this layout file, the new payment method is registered in layout so that it will be included on the checkout page. This XML file contains a reference to the JavaScript component we created.

Now our payment method will be an option during checkout.

Now in order to make our payment method work, we’ll need to update our payment class with logic on how to handle the submitted data.

Payment Method Model

Before our payment model LlamaCoin can be used to process an order, we need to update a few properties: $_canCapture and $_canAuthorize. The payment abstract method class (\Magento\Payment\Model\Method\AbstractMethod) checks these properties before calling the associated methods on our payment model instance. Since we’ll be implementing a capture and authorize method, we will want to change these properties to be true. If your payment method implements methods for voids, refunds, or partial captures, you’ll want to set the corresponding property on your payment method instance. Look through the AbstractMethod class to be familiar with all the available properties.

We’ll need one more property: $_code. The value of this property will be the payment method code that we’re using: “classyllama_llamacoin”. The AbstractMethod class uses this property in the getCode method which is called any time Magento needs to get the payment model code. This means it’s important that the $_code property matches the section name we defined in system.xml. This is used several times, one of which is to set and save the payment method code on the order object.

Now that these properties are in place, we can look at the logic around how an order is processed. When an order is placed, the place method in the \Magento\Sales\Model\Order\Payment class decides how to handle the payment. Several important steps happen during this method:

  1. The place method finds an instance of our payment method model.
  2. The payment is validated. This validation happens in the validate method on the payment model. Since we extended the \Magento\Payment\Model\Method\Cc class, this parent class is used to validate our payment. To customize the validation logic, simply define a validate method in your payment class.
  3. Payment Action. This method determines how the payment will be handled. By default, there are three actions defined as constants on \Magento\Payment\Model\Method\AbstractMethod: order, authorize, and authorize_capture. We’ll need to implement the getConfigPaymentAction method in our class and return the action we want to use. (This option can be made configurable. The Authorize.Net module adds a source model for payment action to make it a configurable field.)
  4. The authorize and capture methods are called. (See full payment model class below.)
  5. We will use two API calls. One to authorize the amount, and one to capture the amount.
  6. Two parameters are passed to the authorize and capture methods. An amount (the total price of the order) and a $payment object which implements the \Magento\Payment\Model\InfoInterface interface. This $payment object will have all data we need to reference set on it. (Credit card data, address info, and order data.) We can now build an array of data to pass to the credit card processor.
  7. makeCaptureRequest and makeAuthRequest have been implemented as placeholder methods that return test data. In reality, these methods would be where you implement specific logic to reach out to the API of a credit card processor.
  8. The capture method first checks to make sure an authorize request has been successful. Once authorization and capture happen, the status of the payment is updated by setting setIsTransationClosed to true.
  9. After the authorize and capture methods, Magento updates the order status and saves the payment data to the database. The order process is now complete!

Here is the final state of the payment method model:


We’ve completed building a custom payment method for Magento. We built the foundational backend configuration settings and model, then we added the frontend changes necessary to display the payment method to the customer, and then added logic to have the model process the payment data. This tutorial can be used as a basis for adding payment methods to Magento. There are many ways to built upon what we’ve done to provide the best experience for the merchant and their customers.

I’ve added all the code for this example to this GitHub. (This example was built and tested on Magento 2.2.2.) Additionally, the Braintree and Authorize.Net modules in the core Magento code provide great examples of how several of these files interact.


  1. mike says:

    I was walking through the tutorial and got a 500 error when i got to the part where you add in the di.xml. Because you are doing an override on Magento\Payment\Model\CcGenericConfigProvider with ClassyLlama\LlamaCoin\Model\LlamaCoin::CODE, Magento will freak out because the Model class doesn’t have the constant in it yet (you add that in at the end). I added that in and all way good with the world again.

  2. Mohammed says:

    Thank you

  3. Yasser Nasser says:

    hello there thank you very much i am searching for this but i have a question of how and where we can add the api of the bank and handling with the request from and to our bank

  4. Jay says:


    I am using capture method . when I printing there something and put exit ;

    I am unable to show anything there and it redirect to checkout/cart .
    can you show me how debug my data .

    I am testing like it goes to checkout/cart Please suggest me How to debug my data .

    public function capture(\Magento\Payment\Model\InfoInterface $payment, $amount)
    echo $amount; exit;

  5. Nice post guys, thanks for sharing to the community!
    PD: I love the Bitcoin image at the top 🙂

  6. Julian says:

    Thank You. I need to redirect the customer to a payment page hosted by the processor. Should the customer be redirected from here ‘ClassyLlama\LlamaCoin\Model\ or from another class or javascript file ?

  7. Nassim B. says:

    Thank you so much, it would have been great to have a step by step schema as a summery just to make things clear in in our mind, just a question did you got inspired by the default payment modules already shipped with magento ? will it help me go faster if i check them ? as i’am now implementing a payment module but with only a button that redirects to the processor gateway.

  8. ramon says:

    How could this work using 3d secure?

  9. TexasRancher says:

    Great guide! What do we use if Cc is deprecated?

  10. Ramkishan says:

    Great explanation

  11. Note that this approach to creating payment methods (inheriting from the Cc class and AbstractMethod in turn) is deprecated (technically has been since Magento 2.0), and it appears it may be removed in Magento 2.4, which will come out sometime this year.

    This Magento Dev Docs section describes the current approach:

  12. ISRAEL GUIDO says:

    I have that error “Constant name is expected.” when i use setup:upgrade, Do you know this ?

  13. ISRAEL GUIDO says:

    How do I render one more payment option? In the same method-render js

  14. MagentoDev says:

    Hey Chris! Thanks for the guide. Any chance you can update it to 2.3 to reflect using DI / di.xml, given that the way you implemented the payment method model is now deprecated in 2.3 and will be removed in the future?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Most Recent PostsView all
October 15, 2021

Classy Llama Wins 2021 Comparably Awards for Best Perks&Benefits, Best Work-Life Balance

Classy Llama, Springfield’s only full-service eCommerce agency, has been placed on the top 50 list for’s Best Perks&Benefits Award, as well as their Best Work-Life […]
September 15, 2021

Classy Llama Awarded #3 Best Place to Work by Biz417

Springfield, MO — Classy Llama has been awarded the number 3 spot on the Biz417 Best Places to Work Top 20 for 2021.  This award is […]
September 13, 2021

2021 Instagram Changes: What you need to know for eCommerce Marketing

What’s Going On With Instagram in 2021? The Head of Instagram, Adam Mosseri, announced in summer 2021 that big changes are coming to the platform sometime […]