Loaded Commerce descends from the osCommerce and Zen Cart lineage, so its payment architecture follows the classic PHP module pattern: each gateway lives as a module under includes/modules/payment/, and server-to-server communication happens through outbound cURL requests plus inbound callback scripts. That design predates the SNI and TLS 1.2+ era, which is exactly why payments that worked for years suddenly stop on a modern managed stack. PayPal, Authorize.Net, Stripe, and most acquirers have retired TLS 1.0/1.1 and older cipher suites. When the PHP build or the module's cURL options still negotiate a legacy handshake, the gateway endpoint simply refuses the connection and the order collapses mid-checkout.
The trouble with diagnosing this on shared hosting is that Loaded Commerce was built to fail quietly. A declined handshake, a blocked callback, or a stale API key all surface to the shopper as the same vague "There has been an error processing your credit card" message, while the real cause sits in a log file the customer rarely looks at. Because you are operating as an unprivileged hosting user, you cannot touch the server's OpenSSL configuration or restart services. Every fix here runs through the Loaded Commerce AdminCP, cPanel or DirectAdmin's PHP Selector and File Manager, .htaccess, .user.ini, and the store's own transaction logs.
Outbound cURL and TLS failures to the gateway
The first category of failure is purely outbound: your store tries to reach the gateway's API endpoint and never completes the handshake. On a LiteSpeed/CloudLinux stack the PHP cURL extension must be enabled and linked against a current OpenSSL, and the selected PHP version must be modern enough to negotiate TLS 1.2 or 1.3. Start in cPanel under Software > Select PHP Version (Jupiter) or DirectAdmin under Account Manager > Select PHP Version. Confirm the store runs PHP 7.4 or newer, then verify that the curl and openssl extensions are checked. Loaded Commerce still works under older PHP, but PHP 5.x links against OpenSSL versions that cannot complete a modern handshake, and no module setting can rescue that.
To see what is actually happening, create a one-off diagnostic file in your account root with File Manager. Name it something unguessable like tlscheck-8831.php and place it outside the web root if possible, or delete it immediately after use:
<?php
$ch = curl_init('https://api.paypal.com/');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
$out = curl_exec($ch);
if ($out === false) {
echo 'cURL error: ' . curl_error($ch);
} else {
echo 'Handshake OK';
}
$info = curl_version();
echo "\nSSL version: " . $info['ssl_version'];
curl_close($ch);
If that prints SSL version: OpenSSL/1.1.1 or newer and "Handshake OK", the stack itself is sound and the problem is inside the module. If it returns errors like SSL connect error or unsupported protocol, switch PHP versions in the Select PHP Version panel and re-run the test. Older Loaded Commerce payment modules sometimes hardcode CURLOPT_SSLVERSION to a legacy constant or disable peer verification to work around expired bundles. Open the gateway file under includes/modules/payment/ in File Manager and remove any line forcing CURL_SSLVERSION_TLSv1_0 or setting CURLOPT_SSL_VERIFYPEER to false. Let the current build negotiate automatically. A common error number worth memorizing is cURL 60 (SSL certificate problem), which usually means the CA bundle the module references is stale rather than the connection being blocked. Rather than pointing CURLOPT_CAINFO at a bundled cacert.pem you shipped years ago, comment that line out so cURL falls back to the server's maintained CA store.
Inbound IPN and webhook callbacks reaching the store
The second category is inbound: the gateway tries to POST a notification back to your store and the request is rejected, rewritten, or lost. Loaded Commerce uses callback scripts such as ext/modules/payment/paypal/ipn.php and similar handlers for other processors. These endpoints must be publicly reachable over HTTPS, must not require a session cookie, and must not be caught by security rules meant for human visitors.
The most frequent silent killer is a .htaccess rule that challenges or blocks non-browser traffic. Hotlink protection, bot filters, or a blanket "block empty user agents" rule will intercept a PayPal IPN POST because gateways often send no referer and a minimal user agent. Review your document root .htaccess and the store subdirectory for mod_rewrite conditions that filter on HTTP_USER_AGENT or HTTP_REFERER. Carve out an explicit exception for the callback path before any blocking rule:
<IfModule mod_rewrite.c>
RewriteEngine On
# Allow gateway callbacks through untouched
RewriteCond %{REQUEST_URI} ^/ext/modules/payment/.*ipn\.php$ [NC]
RewriteRule .* - [L]
</IfModule>
If you run any basic-auth or IP restriction over the admin or store, make sure it does not cover the callback directory. Test reachability yourself by requesting the IPN URL directly in a browser: a healthy endpoint returns a blank page or a short acknowledgment with HTTP 200, not a 403, 401, or a redirect to a login. A 301/302 redirect is its own problem. If your store forces HTTPS or forces www with a rewrite, the gateway may follow the redirect inconsistently or strip the POST body on the hop. Make sure the callback URL you register in the AdminCP already matches the canonical scheme and host exactly, so no redirect ever fires for that request. For deeper reading on verifying callback delivery and outbound TLS on the same class of PHP cart, the Sylius payments and webhooks guide covers the same handshake and callback principles.
API credentials, live/sandbox mode, and currency mismatches
When the handshake succeeds and callbacks arrive but transactions still decline, the fault is almost always in the gateway configuration inside the AdminCP. Navigate to Modules > Payment in the Loaded Commerce admin, open the active gateway, and work through its fields methodically. The classic mistakes are leaving the module in Test/Sandbox mode while using live credentials (or the reverse), pasting an API login ID with trailing whitespace, or swapping the transaction key with the signature key. Authorize.Net modules in particular fail with a generic error when the Login ID and Transaction Key belong to different environments.
Currency and transaction-type settings matter too. If the store currency configured under Localization > Currencies is not one the gateway account supports, the processor rejects the capture even though credentials are valid. Confirm the ISO code and that the gateway module's own currency field agrees with the store default. For PayPal, ensure the account email or merchant ID in the module exactly matches the receiving account; a mismatched business email makes IPN messages arrive but mark as "invalid" so orders never flip to paid. After any credential change, clear the store cache if your build caches module config, and place a one-cent or sandbox order rather than trusting the "test connection" button, which only validates reachability and not authorization.
Reading transaction logs and PHP errors
Loaded Commerce does not expose a rich payment log by default, so correlate three sources. First, enable the gateway's own debug/logging option in its module settings where available; PayPal and Authorize.Net modules can write to a file under the store directory. Second, watch the PHP error_log that your hosting generates. In cPanel File Manager, enable "Show Hidden Files" and look for error_log in the store's root and in includes/. To force PHP to record warnings during a test checkout, add a per-directory .user.ini in the store root:
log_errors = On
error_log = /home/USERNAME/phperr/lc_errors.log
display_errors = Off
max_execution_time = 60Replace USERNAME with your account and create the phperr directory first. Keep display_errors off so you never leak stack traces to shoppers. Third, cross-reference the gateway's merchant portal, which shows whether the authorization ever reached the processor at all. If the portal has no record, the failure is outbound (cURL/TLS); if the portal shows an approval but your store shows an unpaid order, the failure is the inbound callback. That single distinction tells you which of the sections above to work through, and it keeps you from changing credentials when the real issue was a blocked IPN, or editing .htaccess when the handshake never left the server.