A payment system is a critically important component of an online store. In this article, we'll look at integrating popular payment providers into OpenCart.
General Payment Module Architecture
Each payment module in OpenCart 4 consists of:
- Admin Controller — module settings
- Catalog Controller — payment processing
- Model — database interaction
- Twig templates — payment form
LiqPay Integration
LiqPay is a popular payment system in Ukraine:
<?php
// catalog/controller/extension/payment/liqpay.php
namespace Opencart\Catalog\Controller\Extension\Payment;
class Liqpay extends \Opencart\System\Engine\Controller {
public function index(): string {
$this->load->language('extension/payment/liqpay');
$order_id = $this->session->data['order_id'];
$this->load->model('checkout/order');
$order = $this->model_checkout_order->getOrder($order_id);
$data = base64_encode(json_encode([
'version' => 3,
'public_key' => $this->config->get('payment_liqpay_public_key'),
'action' => 'pay',
'amount' => $order['total'],
'currency' => $order['currency_code'],
'description' => 'Order #' . $order_id,
'order_id' => $order_id,
'result_url' => $this->url->link('checkout/success'),
'server_url' => $this->url->link('extension/payment/liqpay|callback')
]));
$signature = base64_encode(sha1(
$this->config->get('payment_liqpay_private_key') .
$data .
$this->config->get('payment_liqpay_private_key'),
true
));
return $this->load->view('extension/payment/liqpay', [
'data' => $data,
'signature' => $signature
]);
}
public function callback(): void {
$data = json_decode(base64_decode($_POST['data']), true);
// Signature verification
$signature = base64_encode(sha1(
$this->config->get('payment_liqpay_private_key') .
$_POST['data'] .
$this->config->get('payment_liqpay_private_key'),
true
));
if ($signature !== $_POST['signature']) {
die('Invalid signature');
}
if ($data['status'] === 'success') {
$this->load->model('checkout/order');
$this->model_checkout_order->addHistory(
$data['order_id'],
$this->config->get('payment_liqpay_order_status_id'),
'LiqPay payment successful'
);
}
}
}
Stripe Integration
// Using Stripe PHP SDK
require_once DIR_SYSTEM . 'library/stripe/autoload.php';
\Stripe\Stripe::setApiKey($this->config->get('payment_stripe_secret_key'));
$paymentIntent = \Stripe\PaymentIntent::create([
'amount' => $order['total'] * 100, // in cents
'currency' => strtolower($order['currency_code']),
'metadata' => [
'order_id' => $order_id
]
]);
// Webhook handling
$payload = file_get_contents('php://input');
$sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'];
$event = \Stripe\Webhook::constructEvent(
$payload,
$sig_header,
$this->config->get('payment_stripe_webhook_secret')
);
if ($event->type === 'payment_intent.succeeded') {
$order_id = $event->data->object->metadata->order_id;
// Update order status
}
Use webhooks for payment confirmation instead of redirect. The client may close the browser before redirect.
— Best Practice
PayPal Checkout
// Frontend: PayPal JavaScript SDK
paypal.Buttons({
createOrder: function(data, actions) {
return fetch('/index.php?route=extension/payment/paypal|createOrder', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({order_id: orderId})
})
.then(res => res.json())
.then(data => data.paypal_order_id);
},
onApprove: function(data, actions) {
return fetch('/index.php?route=extension/payment/paypal|captureOrder', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({paypal_order_id: data.orderID})
})
.then(res => res.json())
.then(data => {
if (data.success) {
window.location.href = '/checkout/success';
}
});
}
}).render('#paypal-button-container');
Testing Payments
- LiqPay: sandbox mode in settings
- Stripe: test keys + card 4242424242424242
- PayPal: sandbox accounts
Logging and Monitoring
// Payment logging
$this->log->write('Payment: Order #' . $order_id . ' - Status: ' . $status);
// Log structure
[
'timestamp' => date('Y-m-d H:i:s'),
'order_id' => $order_id,
'payment_method' => 'liqpay',
'amount' => $amount,
'status' => $status,
'transaction_id' => $transaction_id
]
Conclusion
Proper payment system integration ensures security and convenience for customers. Don't forget about webhook confirmation, logging, and testing all scenarios.