skills/payment-method-development/SKILL.md
Payment gateway development in Bagisto. Activates when creating payment methods, integrating payment gateways like Stripe, PayPal, or any third-party payment processor; or when the user mentions payment, payment gateway, payment method, Stripe, PayPal, or needs to add a new payment option to the checkout.
npx skillsauth add bagisto/agent-skills payment-method-developmentInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Creating custom payment methods in Bagisto allows you to integrate any payment gateway or processor with your store. Whether you need local payment methods, cryptocurrency payments, or specialized payment flows, custom payment methods provide the flexibility your business requires.
For our tutorial, we'll create a Custom Stripe Payment method that demonstrates all the essential concepts you need to build any type of payment solution.
Activate this skill when:
Bagisto's payment system is built around a flexible method-based architecture that separates configuration from business logic.
| Component | Purpose | Location |
|-----------|---------|----------|
| Payment Methods Configuration | Defines payment method properties | Config/payment-methods.php |
| Payment Classes | Contains payment processing logic | Payment/ClassName.php |
| System Configuration | Admin interface forms | Config/system.php |
| Service Provider | Registers payment method | Providers/ServiceProvider.php |
mkdir -p packages/Webkul/CustomStripePayment/src/{Payment,Config,Providers}
File: packages/Webkul/CustomStripePayment/src/Config/payment-methods.php
<?php
return [
'custom_stripe_payment' => [
'code' => 'custom_stripe_payment',
'title' => 'Credit Card (Stripe)',
'description' => 'Secure credit card payments powered by Stripe',
'class' => 'Webkul\CustomStripePayment\Payment\CustomStripePayment',
'active' => true,
'sort' => 1,
],
];
| Property | Type | Purpose | Description |
|----------|------|---------|-------------|
| code | String | Unique identifier | Must match the array key and be used consistently across your payment method. |
| title | String | Default display name | Shown to customers during checkout (can be overridden in admin). |
| description | String | Payment method description | Brief explanation of the payment method. |
| class | String | Payment class namespace | Full path to your payment processing class. |
| active | Boolean | Default status | Whether the payment method is enabled by default. |
| sort | Integer | Display order | Lower numbers appear first in checkout (0 = first). |
Note: The array key (
custom_stripe_payment) must match thecodeproperty and be used consistently in your payment class$codeproperty, system configuration key path, and route names and identifiers.
File: packages/Webkul/CustomStripePayment/src/Payment/CustomStripePayment.php
<?php
namespace Webkul\CustomStripePayment\Payment;
use Webkul\Payment\Payment\Payment;
class CustomStripePayment extends Payment
{
/**
* Payment method code - must match payment-methods.php key.
*
* @var string
*/
protected $code = 'custom_stripe_payment';
/**
* Get redirect URL for payment processing.
*
* Note: You need to create this route in your Routes/web.php file
* or return null if you don't need a redirect.
*
* @return string|null
*/
public function getRedirectUrl()
{
// return route('custom_stripe_payment.process');
return null; // No redirect needed for this basic example
}
/**
* Get additional details for frontend display.
*
* @return array
*/
public function getAdditionalDetails()
{
return [
'title' => $this->getConfigData('title'),
'description' => $this->getConfigData('description'),
'requires_card_details' => true,
];
}
/**
* Get payment method configuration data.
*
* @param string $field
* @return mixed
*/
public function getConfigData($field)
{
return core()->getConfigData('sales.payment_methods.custom_stripe_payment.' . $field);
}
}
File: packages/Webkul/CustomStripePayment/src/Config/system.php
<?php
return [
[
'key' => 'sales.payment_methods.custom_stripe_payment',
'name' => 'Custom Stripe Payment',
'info' => 'Custom Stripe Payment Method Configuration',
'sort' => 1,
'fields' => [
[
'name' => 'active',
'title' => 'Status',
'type' => 'boolean',
'default_value' => true,
'channel_based' => true,
],
[
'name' => 'title',
'title' => 'Title',
'type' => 'text',
'default_value' => 'Credit Card (Stripe)',
'channel_based' => true,
'locale_based' => true,
],
[
'name' => 'description',
'title' => 'Description',
'type' => 'textarea',
'default_value' => 'Secure credit card payments',
'channel_based' => true,
'locale_based' => true,
],
[
'name' => 'sort',
'title' => 'Sort Order',
'type' => 'text',
'default_value' => '1',
],
],
],
];
| Property | Purpose | Description |
|----------|---------|-------------|
| name | Field identifier | Used to store and retrieve configuration values. |
| title | Field label | Label displayed in the admin form. |
| type | Input type | text, textarea, boolean, select, password, etc. |
| default_value | Default setting | Initial value when first configured. |
| channel_based | Multi-store support | Different values per sales channel. |
| locale_based | Multi-language support | Translatable content per language. |
| validation | Field validation | Rules like required, numeric, email. |
File: packages/Webkul/CustomStripePayment/src/Providers/CustomStripePaymentServiceProvider.php
<?php
namespace Webkul\CustomStripePayment\Providers;
use Illuminate\Support\ServiceProvider;
class CustomStripePaymentServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register(): void
{
// Merge payment method configuration.
$this->mergeConfigFrom(
dirname(__DIR__) . '/Config/payment-methods.php',
'payment_methods'
);
// Merge system configuration.
$this->mergeConfigFrom(
dirname(__DIR__) . '/Config/system.php',
'core'
);
}
/**
* Bootstrap services.
*
* @return void
*/
public function boot(): void
{
//
}
}
{
"autoload": {
"psr-4": {
"Webkul\\CustomStripePayment\\": "packages/Webkul/CustomStripePayment/src"
}
}
}
composer dump-autoload
bootstrap/providers.php:<?php
return [
App\Providers\AppServiceProvider::class,
// ... other providers ...
Webkul\CustomStripePayment\Providers\CustomStripePaymentServiceProvider::class,
];
php artisan optimize:clear
Location: packages/Webkul/Payment/src/Payment/Payment.php
All payment methods extend Webkul\Payment\Payment\Payment abstract class:
<?php
namespace Webkul\Payment\Payment;
use Webkul\Checkout\Facades\Cart;
abstract class Payment
{
/**
* Cart.
*
* @var \Webkul\Checkout\Contracts\Cart
*/
protected $cart;
/**
* Checks if payment method is available.
*
* @return bool
*/
public function isAvailable()
{
return $this->getConfigData('active');
}
/**
* Get payment method code.
*
* @return string
*/
public function getCode()
{
if (empty($this->code)) {
// throw exception
}
return $this->code;
}
/**
* Get payment method title.
*
* @return string
*/
public function getTitle()
{
return $this->getConfigData('title');
}
/**
* Get payment method description.
*
* @return string
*/
public function getDescription()
{
return $this->getConfigData('description');
}
/**
* Get payment method image.
*
* @return string
*/
public function getImage()
{
return $this->getConfigData('image');
}
/**
* Retrieve information from payment configuration.
*
* @param string $field
* @return mixed
*/
public function getConfigData($field)
{
return core()->getConfigData('sales.payment_methods.'.$this->getCode().'.'.$field);
}
/**
* Abstract method to get the redirect URL.
*
* @return string The redirect URL.
*/
abstract public function getRedirectUrl();
/**
* Set cart.
*
* @return void
*/
public function setCart()
{
if (! $this->cart) {
$this->cart = Cart::getCart();
}
}
/**
* Get cart.
*
* @return \Webkul\Checkout\Contracts\Cart
*/
public function getCart()
{
if (! $this->cart) {
$this->setCart();
}
return $this->cart;
}
/**
* Return cart items.
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function getCartItems()
{
if (! $this->cart) {
$this->setCart();
}
return $this->cart->items;
}
/**
* Get payment method sort order.
*
* @return string
*/
public function getSortOrder()
{
return $this->getConfigData('sort');
}
/**
* Get payment method additional information.
*
* @return array
*/
public function getAdditionalDetails()
{
if (empty($this->getConfigData('instructions'))) {
return [];
}
return [
'title' => trans('admin::app.configuration.index.sales.payment-methods.instructions'),
'value' => $this->getConfigData('instructions'),
];
}
}
| Method | Purpose | Required |
|--------|---------|----------|
| getRedirectUrl() | Return URL for redirect payment methods | Yes (abstract) |
| getImage() | Return payment method logo URL | No (uses default) |
| getAdditionalDetails() | Return additional info (instructions, etc.) | No (uses default) |
| isAvailable() | Override to add custom availability logic | No (uses default) |
| getConfigData($field) | Override if codes are not in convention | No (uses default) |
Implementation Note: Usually, you don't need to explicitly set the
$codeproperty because if your codes are properly set, then config data can get properly. However, if codes are not in convention then you might need this property to override the default behavior.
packages/Webkul/Payment/src/Payment/CashOnDelivery.phppackages/Webkul/Payment/src/Payment/MoneyTransfer.phppackages/Webkul/Paypal/src/Payment/Standard.phppackages/Webkul/Paypal/src/Payment/SmartButton.phpAlways implement comprehensive error handling in your payment methods:
/**
* Handle payment errors gracefully.
*
* @param \Exception $e
* @return array
*/
protected function handlePaymentError(\Exception $e)
{
// Log the error for debugging.
\Log::error('Payment error in ' . $this->code, [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
// Return user-friendly error message.
return [
'success' => false,
'error' => 'Payment processing failed. Please try again or contact support.',
];
}
Always validate and sanitize data before processing payments to protect your application and customers:
/**
* Validate payment data before processing.
*
* @param array $data
* @return bool
*
* @throws \InvalidArgumentException
*/
protected function validatePaymentData($data)
{
$validator = validator($data, [
'amount' => 'required|numeric|min:0.01',
'currency' => 'required|string|size:3',
'customer_email'=> 'required|email',
]);
if ($validator->fails()) {
throw new \InvalidArgumentException($validator->errors()->first());
}
return true;
}
Proper logging helps you track payment activities and troubleshoot issues without exposing sensitive information:
/**
* Log payment activities for debugging and audit.
*
* @param string $action
* @param array $data
* @return void
*/
protected function logPaymentActivity($action, $data = [])
{
// Remove sensitive data before logging.
$sanitizedData = array_diff_key($data, [
'api_key' => '',
'secret_key' => '',
'card_number' => '',
'cvv' => '',
]);
\Log::info("Payment {$action} for {$this->code}", $sanitizedData);
}
Implementation Note: The methods shown in this section are demonstration examples for best practices. In real-world applications, you need to implement these methods according to your specific payment gateway requirements and business logic. Use these examples as reference guides and adapt them to your particular use case.
For complex payment integrations like PayPal, see packages/Webkul/Paypal/src/Payment/SmartButton.php:
packages
└── Webkul
└── CustomStripePayment
└── src
├── Payment
│ └── CustomStripePayment.php # Payment processing logic
├── Config
│ ├── payment-methods.php # Payment method definition
│ └── system.php # Admin configuration
└── Providers
└── CustomStripePaymentServiceProvider.php # Registration
Payment methods can be tested using the checkout tests in packages/Webkul/Shop/tests/Feature/Checkout/CheckoutTest.php.
| File | Purpose |
|------|---------|
| packages/Webkul/Payment/src/Payment/Payment.php | Base abstract class |
| packages/Webkul/Payment/src/Payment.php | Payment facade methods |
| packages/Webkul/Payment/src/Config/paymentmethods.php | Default payment methods config |
| packages/Webkul/Paypal/src/Payment/SmartButton.php | Complex payment example |
| packages/Webkul/Paypal/src/Providers/PaypalServiceProvider.php | Service provider example |
| packages/Webkul/Payment/src/Payment/CashOnDelivery.php | Simple payment example |
| packages/Webkul/Payment/src/Payment/MoneyTransfer.php | Payment with additional details |
$code property with config array keybootstrap/providers.phpcomposer dump-autoload after adding packagedevelopment
Shop theme development in Bagisto. Activates when creating custom storefront themes, modifying shop layouts, building theme packages, or working with Vite-powered assets for the customer-facing side of the application.
development
Shipping method development in Bagisto. Activates when creating shipping methods, integrating shipping carriers like FedEx, UPS, DHL, or any third-party shipping provider; or when the user mentions shipping, shipping method, shipping carrier, delivery, or needs to add a new shipping option to checkout.
development
Product type development in Bagisto. Activates when creating custom product types, defining product behaviors, or implementing specialized product logic. Use references: @config (product type configuration), @abstract (AbstractType methods), @build (complete subscription implementation).
development
Tests applications using the Pest 3 PHP framework in Bagisto. Activates when writing tests, creating unit or feature tests, adding assertions, testing Livewire components, architecture testing, debugging test failures, working with datasets or mocking; or when the user mentions test, spec, TDD, expects, assertion, coverage, or needs to verify functionality works.