How PrestaShop Processes Payments and Webhooks
A PrestaShop order moves through several states before it is confirmed, and most payment problems happen in the gap between the customer leaving your store and the gateway sending a result back. When a shopper clicks the final payment button, PrestaShop hands control to a payment module (Stripe, PayPal, Mollie, Redsys, or a bank-provided module). The customer is redirected to the gateway, completes the transaction, and two things need to happen next: the browser returns to your return URL, and the gateway sends a server-to-server notification, commonly called a webhook, IPN, or callback, to a dedicated controller inside your module such as /module/stripe_official/validation or /module/paypal/ipn.
The order status only changes to "Payment accepted" when PrestaShop validates that incoming notification. The customer-facing redirect is unreliable by design because browsers can be closed mid-redirect, so the webhook is the authoritative signal. If that server-to-server call never arrives, never validates, or the module cannot phone home to confirm it, you get the classic symptom: money leaves the customer's account but the order sits in "Awaiting payment" or disappears into an abandoned cart. On managed shared hosting with LiteSpeed, AlmaLinux, and CloudLinux, the usual culprits are outbound cURL restrictions, an outdated TLS stack exposed to PHP, mangled API credentials, or rewrite rules that block the incoming webhook path.
Before changing anything, confirm where the failure sits. Log into the PrestaShop back office and open Orders > Orders to see whether paid transactions are landing. Then open Advanced Parameters > Logs, which records PHP-level and module-level exceptions that PrestaShop itself caught. For raw PHP fatals and cURL errors you will need the file-based log, which on shared hosting lives alongside your store files rather than in a system directory you cannot reach.
Diagnosing Outbound cURL and TLS Failures
Most modern gateways require your server to make outbound HTTPS calls: to capture a payment, to verify a webhook signature, or to fetch an access token. When the store cannot reach the gateway, PrestaShop logs errors like cURL error 7: Failed to connect, cURL error 35: SSL connect error, or cURL error 60: SSL certificate problem. These point at the PHP extensions and TLS libraries compiled into your selected PHP version, not at PrestaShop code.
Start by confirming the active PHP version and extensions. In cPanel Jupiter, open Select PHP Version (the PHP Selector under CloudLinux); in DirectAdmin Evolution, open Select PHP Version or PHP Selector from the user panel. PrestaShop 1.7.8+ and PrestaShop 8 expect PHP 7.4 through 8.1 depending on your version, and the payment modules need both curl and openssl enabled. Tick those extensions and save. An outdated PHP build is the single most common cause of cURL error 35 because gateways such as Stripe and PayPal now reject anything below TLS 1.2. Moving from PHP 7.2 to PHP 8.1 usually pulls in a current OpenSSL and resolves the handshake outright.
To see exactly what your account can reach, create a short diagnostic file through File Manager in the document root (for example public_html/curltest.php) with this content:
<?php
$ch = curl_init('https://api.stripe.com/v1');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
$result = curl_exec($ch);
if (curl_errno($ch)) {
echo 'cURL error ' . curl_errno($ch) . ': ' . curl_error($ch);
} else {
echo 'Connection OK, HTTP ' . curl_getinfo($ch, CURLINFO_HTTP_CODE);
}
curl_close($ch);
Load it once in a browser, read the result, then delete the file immediately so it is not left exposed. "Connection OK" with any HTTP code means outbound TLS works and the problem lies in credentials or the webhook path. A cURL error 60 (certificate problem) indicates a stale CA bundle; on a managed platform you cannot edit /etc/, so the correct fix is switching to a newer PHP version in the selector, which ships a current cacert.pem. Never work around this by setting CURLOPT_SSL_VERIFYPEER to false in production, because that disables the very verification a payment gateway relies on. A cURL error 7 suggests outbound connections on port 443 are being blocked or throttled; open a ticket with Hostiso support so the firewall can be checked for your account, since that is a server-side control an unprivileged user cannot adjust.
Fixing Webhook Delivery, Rewrites, and Credentials
Once outbound calls succeed, confirm the gateway can reach your webhook endpoint. Each gateway publishes the delivery log on its own dashboard: Stripe shows it under Developers > Webhooks, PayPal under Webhooks in the developer app, and Mollie under the website profile. Look for the HTTP status returned to the gateway. A 404 means the controller URL is wrong or friendly URLs are off; a 403 means something is blocking the request; a 500 means PrestaShop accepted the call but threw a fatal while processing it.
PrestaShop friendly URLs depend on rewrite rules. In the back office under Shop Parameters > Traffic & SEO, confirm "Friendly URL" is enabled, then open File Manager and verify public_html/.htaccess still contains the PrestaShop rewrite block. If you edited .htaccess for security and accidentally blocked the module path, callbacks break. A safe rule that keeps webhook controllers reachable while blocking direct access to sensitive directories looks like this:
# Allow module webhook controllers through
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/module/ [NC]
RewriteRule ^ - [L]
# Block direct access to internal folders
RewriteRule ^(app|bin|cache|config|var|translations)/ - [F,L]
If you use a hotlink or bot-protection ruleset that filters by User-Agent, allow-list the gateway. PayPal IPN and Stripe send requests without a standard browser User-Agent, so an aggressive Deny rule returns 403 and the gateway marks delivery as failed. Remove or relax any SetEnvIfNoCase User-Agent blocks that match empty or non-browser agents on the /module/ path.
Credential errors surface as 401 Unauthorized or authentication_error in Advanced Parameters > Logs. Re-enter keys in the module configuration under Modules > Module Manager, open the gateway module, and paste fresh values. The frequent mistakes are leaving test-mode keys in a live store, pasting a trailing space, or storing the webhook signing secret in the wrong field. For signed webhooks, the signing secret shown on the gateway dashboard must match the field in the module exactly, otherwise PrestaShop rejects a technically valid notification with a signature-mismatch entry in the log.
Timeouts during capture or token exchange point at PHP limits rather than the gateway. Because you cannot edit php.ini directly, create or edit public_html/.user.ini to raise execution and memory ceilings for slow gateway responses:
max_execution_time = 120
max_input_time = 120
memory_limit = 512M
default_socket_timeout = 60LiteSpeed reads .user.ini per directory; allow a few minutes for the change to take effect or clear the LiteSpeed cache from the back office. This pattern of callback, credential, and TLS troubleshooting is consistent across PHP e-commerce platforms, and the same logic applies to Drupal Commerce payment webhooks on shared hosting if you run multiple stores.
Verifying Transaction Logging and Recovering Stuck Orders
After each fix, trigger a real test. Most gateways let you resend a webhook from their dashboard delivery log, which is faster than placing a new order. Resend the event and immediately check Advanced Parameters > Logs; a clean validation adds an "Order validated" entry and the order moves to "Payment accepted". If the dashboard shows a 200 but the order status never changes, the controller reached PrestaShop but silently failed, so inspect the per-store error_log file that File Manager shows inside the module directory or document root for the exact PHP fatal.
For orders already stuck because the webhook failed earlier, confirm payment on the gateway dashboard first, then update the order manually in Orders > Orders by selecting the order and setting the status to "Payment accepted", which releases stock and sends the confirmation email. Avoid editing order state directly in phpMyAdmin unless you fully understand the ps_order_history and ps_order_state relationship, because a mismatched status leaves the order in an inconsistent state that breaks invoicing. Once credentials, TLS, and rewrites are correct, webhooks deliver reliably and manual intervention becomes the rare exception rather than the daily routine.