Xgenious/ docs

Creating a Gateway

Step 2: Entry Class

<?php
declare(strict_types=1);

namespace MyPaymentGateway;

use PluginsFramework\Plugins\PluginContext;
use PluginsFramework\Plugins\PluginInterface;

final class MyPaymentGatewayPlugin implements PluginInterface
{
    public function __construct(private PluginContext $ctx) {}

    public function boot(): void
    {
        // 1. Register gateway with core
        $this->ctx->registry->register('gateway', 'mygateway', [
            'id'               => 'mygateway',
            'label'            => 'My Gateway',
            'module'           => 'MyPaymentGateway',
            'ipn_route'        => 'mygateway.ipn',
            'settings_prefix'  => 'mygateway',
            'enabled_option'   => 'mygateway_gateway',
        ]);

        // 2. Register admin menu (optional)
        $this->ctx->registry->register('admin.menu', 'my-payment-gateway', [
            'label'       => 'My Gateway',
            'route'       => '/admin/mygateway',
            'icon'        => 'fa-solid fa-credit-card',
            'permissions' => 'mygateway-settings',
        ]);

        // 3. Hook into payment.charge filter
        $this->ctx->hooks->addFilter('payment.charge', function (mixed $result, mixed $context = []): mixed {
            if ($result !== null) return $result; // Another plugin handled it

            $context = is_array($context) ? $context : [];
            if (($context['gateway'] ?? '') !== 'mygateway') return $result;

            $args = is_array($context['args'] ?? null) ? $context['args'] : [];

            try {
                return MyGateway::chargeRedirect($args);
            } catch (\Throwable $e) {
                report($e);
                return back()->with('error', $e->getMessage());
            }
        });
    }
}

Step 3: Gateway Logic Class

<?php
declare(strict_types=1);

namespace MyPaymentGateway;

final class MyGateway
{
    public const GATEWAY_ID = 'mygateway';

    public static function opt(string $key, mixed $default = null): mixed
    {
        return function_exists('get_static_option')
            ? get_static_option($key) ?? $default
            : $default;
    }

    public static function enabled(): bool
    {
        return !empty(self::opt('mygateway_gateway'));
    }

    public static function getApiKey(): string
    {
        return (string) self::opt('mygateway_api_key', '');
    }

    public static function isTestMode(): bool
    {
        return !empty(self::opt('mygateway_test_mode'));
    }

    /**
     * Build the redirect URL to the provider's hosted payment page.
     *
     * $args contains:
     *   - amount, title, description, ipn_url, order_id,
     *   - track, cancel_url, success_url, email, name, payment_type
     */
    public static function chargeRedirect(array $args): \Symfony\Component\HttpFoundation\Response
    {
        $apiKey = self::getApiKey();
        $amount = $args['amount'] ?? 0;
        $track  = $args['track'] ?? bin2hex(random_bytes(16));
        $ipnUrl = $args['ipn_url'] ?? '';

        $providerUrl = self::isTestMode()
            ? 'https://sandbox.provider.com/pay'
            : 'https://api.provider.com/pay';

        $params = [
            'key'         => $apiKey,
            'amount'      => number_format($amount, 2, '.', ''),
            'currency'    => 'USD',
            'order_id'    => $track,
            'return_url'  => $args['success_url'] ?? '',
            'cancel_url'  => $args['cancel_url'] ?? '',
            'notify_url'  => $ipnUrl,
            'buyer_name'  => $args['name'] ?? '',
            'buyer_email' => $args['email'] ?? '',
        ];

        $url = $providerUrl . '?' . http_build_query($params);

        return redirect()->away($url);
    }

    /**
     * Verify provider webhook/IPN signature.
     */
    public static function verifyWebhook(\Illuminate\Http\Request $request): bool
    {
        $signature = $request->header('X-Signature', '');
        $body      = $request->getContent();
        $secret    = self::getApiKey();

        $expected = hash_hmac('sha256', $body, $secret);

        return hash_equals($expected, $signature);
    }

    /**
     * Parse provider response to extract payment details.
     */
    public static function parseWebhook(\Illuminate\Http\Request $request): array
    {
        $data = $request->all();

        return [
            'payment_type'   => $data['payment_type'] ?? '',
            'record_id'      => (int) ($data['record_id'] ?? 0),
            'transaction_id' => $data['transaction_id'] ?? null,
            'amount'         => (float) ($data['amount'] ?? 0),
            'status'         => $data['status'] ?? '',
        ];
    }
}

Last updated: September 2026

Still stuck?
Our support team is ready to help you get set up.
Get support