What "payments" actually mean in phpList

phpList is an email newsletter and campaign manager, not a shopping cart. It does not ship a checkout page, a cart, or a built-in payment gateway. Because of that, the usual e-commerce troubleshooting around order totals and card tokens simply does not apply here. What phpList does have is an extensive set of outbound HTTP workflows that behave exactly like webhook and callback traffic, and these are the pieces that break on shared hosting in ways that look identical to a failed payment integration.

The most common money-adjacent setup is a donation or paid-subscription form hosted on an external gateway (PayPal, Stripe Checkout, a WooCommerce store) that, on success, posts the subscriber's email into phpList. That inbound post usually hits the public subscribe endpoint at /lists/?p=subscribe&id=1 or the REST API plugin at /lists/admin/?page=call&pi=restapi. In the other direction, phpList makes outbound calls of its own: remote message processing via /lists/admin/index.php?page=processqueue calling back to the phpList.com infrastructure, plugin update checks, bounce processing over IMAP/POP, and any custom plugin that pushes transaction events to a CRM. All of these depend on a healthy PHP cURL extension, a valid CA bundle, and the ability to open outbound TLS connections from an unprivileged account.

On a managed LiteSpeed/CloudLinux account you cannot touch the gateway's servers, and you cannot run server-wide commands. Everything you can realistically influence lives in the phpList AdminCP, the config/config.php file, .htaccess, a per-directory .user.ini, and phpMyAdmin. That constraint is what shapes every fix below.

Diagnosing outbound cURL and TLS failures

When a callback silently fails, the first question is whether PHP can make an outbound HTTPS request at all. phpList surfaces this in two places. Inside the AdminCP, open Config > Settings and run the built-in checks, then visit the information page at /lists/admin/?page=about, which reports whether the cURL extension is loaded and what PHP version is active. If cURL is missing, enable it before anything else: in cPanel go to Software > Select PHP Version > Extensions and tick curl; in DirectAdmin use Account Manager > Select PHP Version > Extensions under the PHP Selector. No restart is required because PHP-FPM workers recycle per request on these stacks.

The classic failure once cURL is present is a TLS handshake error such as SSL certificate problem: unable to get local issuer certificate. This happens when PHP's cURL cannot locate a current CA bundle. Do not disable verification, and never patch this with CURLOPT_SSL_VERIFYPEER=false in a plugin, because that quietly accepts forged certificates on exactly the traffic that carries subscriber and payment data. The correct fix on a hosting account is to point PHP at a fresh CA bundle through .user.ini. Create or edit .user.ini in your phpList document root (for example /home/USER/public_html/lists/.user.ini) and add:

curl.cainfo = "/etc/ssl/certs/ca-bundle.crt"
openssl.cafile = "/etc/ssl/certs/ca-bundle.crt"

CloudLinux keeps that bundle current, so referencing it is safe even though you cannot edit it. If your host uses a different path you will see it listed in phpinfo under openssl and curl; generate a quick phpinfo by creating /lists/admin/pi.php containing <?php phpinfo();, read the values, then delete the file immediately. Changes to .user.ini take effect after the user_ini.cache_ttl window (300 seconds by default), so wait a few minutes before retesting rather than assuming the edit failed.

A second recurring cause is an outdated TLS floor. Gateways like Stripe reject anything below TLS 1.2, and an old PHP build negotiating TLS 1.0 will fail the handshake. The reliable fix is to raise the PHP version itself. In the PHP Selector set the domain to PHP 8.1 or newer, which links against a modern OpenSSL and negotiates TLS 1.2/1.3 by default. This also pairs naturally with the OPcache and LiteSpeed work covered in our phpList performance guide, so align the version choice across both.

Callback URLs, .htaccess rules, and API credentials

Inbound callbacks fail for a different reason: the request never reaches phpList, or reaches it stripped of the fields it expects. If your gateway posts to the subscribe page but subscribers are not appearing, confirm the exact endpoint and that it is reachable without a login. The public subscribe handler must not sit behind any directory protection. Check that you have not accidentally left an .htaccess rule like the following in the phpList root, which would block the gateway's POST with a 401:

AuthType Basic
AuthName "Staging"
Require valid-user

If a .htpasswd block exists for staging, scope it so the callback path stays open. A focused allow rule inside .htaccess keeps the rest protected while letting the gateway through:

<RequireAny>
  Require valid-user
  Require expr %{REQUEST_URI} =~ m#^/lists/\?p=asubscribe#
</RequireAny>

Many gateways expect to receive a confirmed redirect URL back. In phpList that is the subscribe page's &jo=0 / thank-you handling, configured under Config > Subscribe pages. Set the subscribe page's final destination to a real HTTPS URL on your domain, because gateways that receive a bare HTTP target over a secure checkout will refuse the redirect as mixed content.

For the REST API plugin, which is how most CRM and payment middleware authenticates into phpList, credentials live in the database and in config/config.php. The plugin requires define('RESTAPI_SECRET', '...') to be set in config.php; edit that file through cPanel File Manager rather than any server config. Rotate the secret there and update the calling system, and never place the secret in a web-readable .txt or inside a comment in a public template. Confirm that config/config.php is not downloadable by requesting it in a browser; it should return a blank page or 403, never source. If it renders as text, your PHP handler is misassigned and you must reselect the PHP version in MultiPHP Manager so the .php extension is handled by the interpreter rather than served statically.

Transaction logging and end-to-end verification

Once connectivity is sound, prove it with logs instead of guessing. phpList writes operational problems to its own event log at Config > View event log, and PHP-level cURL exceptions land in the per-directory error_log that CloudLinux creates in whichever folder the script runs from. For callbacks that means watching /home/USER/public_html/lists/error_log and /home/USER/public_html/lists/admin/error_log. Open them in File Manager, trigger a single test transaction from the gateway's sandbox, and read the newest lines. A clean success leaves no cURL entry; a handshake failure writes the SSL certificate problem string, and a blocked inbound post leaves a 401/403 in the raw access log viewable under cPanel Metrics > Raw Access.

To verify the outbound direction specifically, use the processqueue page. Running /lists/admin/?page=processqueue while a campaign is queued forces phpList to contact its sending and remote-processing endpoints; if that page reports a connection timeout, the problem is outbound TLS or a firewall on the account, not your gateway. For inbound verification, add the subscriber through the gateway sandbox and then query the table directly in phpMyAdmin with SELECT email, confirmed, entered FROM phplist_user_user ORDER BY id DESC LIMIT 5;. Seeing the sandbox address with confirmed = 0 confirms the callback arrived and that only the confirmation step remains. Keep these two tests separate so you always know which leg of the round trip is failing, and you will resolve webhook issues in minutes rather than disabling security controls out of frustration.