P2PXchange Module
Custom Features
P2PXchange - PayMoney Peer To Peer Buy/Sell Addon is an extension for Paymoney - Secure Online Payment Gateway. It adds a peer-to-peer (P2P) marketplace where users publish buy or sell offers (crypto and fiat), other users start trades against those offers, and both sides complete the deal inside a trade room with timers, payment instructions, payment proof, crypto release, optional feedback, and in-trade chat. An optional Node.js (Socket.IO) server can push chat and trade updates in real time; without it, the same features work using HTTP polling.
Manage P2P exchange regions from admin panel
Admin can maintain regions from P2P Exchange > P2P regions. Regions are used when users build offers and when visitors filter the public marketplace.

-
Admin can create, edit, and delete regions (subject to permissions such as view / add / edit / delete P2P exchange region).
-
Only active regions should be used for new offers; inactive entries can be hidden from selection depending on your theme.

Manage payment time from admin panel
Admin defines how long a buyer has to pay after a trade starts. Go to P2P Exchange > P2P payment time.

-
Each payment time record represents a duration (for example 15 minutes, 60 minutes) that advertisers attach to an offer.
-
Payment times have a status so outdated options can be deactivated without deleting history.

Manage fiat gateways from admin panel
Admin configures fiat gateways from P2P Exchange > P2P fiat gateways. These are the payment rails shown on offers (for example mobile money, bank transfer, card) together with per-offer instructions and remarks.

-
Gateways are reusable labels; the actual account numbers and payment details are entered by the user when they create or edit an offer (step that maps payment instructions to each gateway).
-
Multiple gateways can be active so advertisers can offer more than one way to pay.

Manage P2P offers from admin panel
Admin can review and adjust user offers from P2P Exchange > P2P offers.

-
From the list, admin can open an offer, edit fields allowed by policy, and export data (CSV / PDF) where enabled.
-
User search helps locate offers by advertiser.
-
Offer type is buy or sell; status (for example Active) controls visibility on the public marketplace.

Manage P2P transactions from admin panel
Admin monitors live and past trades from P2P Exchange > P2P transactions.

-
The screen lists P2P exchanges (individual trades between an offer creator and an exchanger), with filters and exports similar to offers.
-
User search links trades to wallet users for support.

Manage P2P disputes from admin panel
When users escalate a problem, staff work from P2P Exchange > P2P disputes.

-
Admin opens the discussion thread for a dispute, posts replies, and can change reply status when the case moves forward (permissions such as edit dispute apply).
-
Disputes are tied to the same ledger transactions users see in their wallet history for that P2P exchange.
P2P module settings and dispute reasons from admin panel
P2P settings — global options for the add-on live under P2P Exchange > P2P settings (view / edit permissions).

Dispute reasons — predefined reasons users pick when opening a dispute are maintained under P2P Exchange > P2P dispute reasons, so helpdesk and automation stay consistent.

P2P FAQ from admin panel
Short questions and answers shown on the public P2P page are edited under P2P Exchange > P2P FAQ. Only items marked Active appear to visitors.

Optional real-time chat server (Socket.IO / Node)
For instant chat delivery and live updates to the trade page (status, proof areas, review blocks), the module ships with a small Node process:
- Path on disk:
Modules/P2PXchange/socket-server/ - The Node service must use the same
APP_KEYas Laravel. - Choose the chat connection and service URLs from Admin > P2P Exchange > Settings. Laravel's
P2P_SOCKET_*environment settings provide configuration defaults; saved admin settings take precedence. - Follow the cPanel setup guide for hosting managed through cPanel, or the VPS setup guide for a server you manage over SSH.
If this service is not running, chat and trading still work; the browser polls the server every few seconds for new messages and can refresh trade fragments on a timer or navigation.
Socket.IO setup guide for cPanel
Use this guide to run the bundled Socket.IO service through cPanel and connect it to PayMoney. All domain examples use example.com; replace it with your own domain. The screenshots are from a real setup, with identifying details cropped or redacted.
1. Find the Node.js application controls in cPanel
- Sign in to your hosting account and open cPanel. Your hosting dashboard may provide a Log in to cPanel button.
- On the cPanel home screen, use Search Tools and search for Node.js.
- Open Setup Node.js App. Depending on the host's layout, you can also find it in the Software section.
- If that option is missing, search for Application Manager. This is a different interface; use the Application Manager instructions in step 3 below.
After opening Setup Node.js App, you will see the Web Applications list. An empty list with No applications found is normal before the first application is registered.

This screenshot shows the application list after opening the tool. The Search Tools field is at the top right; cPanel's home screen and search results may look different on your host.
If neither tool appears, contact your hosting provider with this request:
Please enable Node.js application hosting for my cPanel account for example.com, including a supported Node.js LTS runtime, npm dependency installation, and HTTPS/WebSocket routing at /p2p-socket. Please confirm whether I should use Setup Node.js App or Application Manager.
Continue once your host confirms that the feature is available. The host controls which application interfaces and Node.js versions your account can use.
2. Locate the PayMoney installation and module files
- Open cPanel > Domains, find
example.com, and note its Document Root. - Open File Manager and locate the PayMoney directory containing
artisanand.env. Enable Settings > Show Hidden Files if.envis not visible. If the document root points to apublicdirectory, locate the parent application directory containingartisan. - Confirm that these files exist inside the PayMoney directory:
Modules/P2PXchange/socket-server/server.js
Modules/P2PXchange/socket-server/package.json
Modules/P2PXchange/socket-server/package-lock.json
Use that PayMoney directory to determine the Node application's root. The Application root is relative to your cPanel home directory, rather than a website URL or a path beginning with /home/.
PayMoney directory containing artisan |
Application root to enter |
|---|---|
/home/YOUR_ACCOUNT/public_html |
public_html/Modules/P2PXchange/socket-server |
/home/YOUR_ACCOUNT/example.com |
example.com/Modules/P2PXchange/socket-server |
Use the row that matches your actual installation, or build the equivalent path if you installed PayMoney elsewhere. Folder names are case-sensitive on Linux; retain Modules/P2PXchange exactly.
The service loads Laravel's .env from the parent application directory. It must read the same existing APP_KEY that Laravel uses. If the application log reports a missing key, check file access or set the matching key in the Node application's environment variables. Keep the key private and preserve its value.
3. Register the Node.js application
Follow the instructions for the tool you found in step 1.
Using Setup Node.js App (CloudLinux Node.js Selector)
Click CREATE APPLICATION and complete the fields below.
| Field | What to enter |
|---|---|
| Node.js version | A supported LTS release available from your host. |
| Application mode | Production. |
| Application root | The relative socket-server directory identified in step 2, such as example.com/Modules/P2PXchange/socket-server. Enter it without a leading /. |
| Application URL domain | example.com, replaced with your PayMoney website's domain. |
| Application URL path | p2p-socket. Keep this path for the configuration in this guide. |
| Application startup file | server.js. |
| Passenger log file | Optional: a writable log path under your account home, such as /home/YOUR_ACCOUNT/paymoney-p2p-passenger.log. |
The resulting service URL should be https://example.com/p2p-socket for the example domain.
Click CREATE. The registered application should show the following fields and controls.

The screenshot uses an older runtime. Select a currently supported LTS release for production; ask your host to enable one if necessary. Check the official Node.js release status when choosing the version.
Using Application Manager
Open cPanel > Software > Application Manager, then click Register Application. Use P2P Socket as the application name, select example.com as the Deployment Domain, set Base Application URL to /p2p-socket, enter the relative socket-server directory from step 2 as Application Path, and choose Production. Click Deploy.
This interface does not offer the same startup-file and version controls as the screenshot above. Have your hosting provider configure server.js as the Passenger startup file and confirm the supported Node.js runtime and restart procedure. See the cPanel Application Manager documentation for this interface.
4. Install dependencies and restart
Setup Node.js App
- Click Run NPM Install on the application's screen and wait for installation to finish successfully. This installs the dependencies from the socket-server's
package.json. - Click RESTART, or Start App if the service is stopped.
- Use these cPanel controls to manage this service. Keep one running relay instance; its exchange rooms are stored in memory.
Application Manager
Use the application's Enable Dependencies action to install its npm dependencies. Restart the application using the procedure confirmed by your hosting provider.
If installation fails, review the panel error and application log before continuing. The CloudLinux Node.js Selector documentation describes the Setup Node.js App controls.
5. Check that the service is running
Open the health-check address in a browser, replacing example.com with your domain:
https://example.com/p2p-socket/health
The expected response is:
{"ok":true}

If the health check succeeds, continue to step 6. If it shows an error, use the matching entry under Troubleshooting the cPanel connection below before changing application files or chat settings.
6. Configure PayMoney's chat connection
After the health check succeeds, open Admin > P2P Exchange > Settings and find Trade chat.
| Field | Value |
|---|---|
| Chat connection | Socket.IO — instant updates. |
| Public socket URL | https://example.com/p2p-socket |
| Internal broadcast URL | https://example.com/p2p-socket/internal/broadcast |
The updated module derives both URLs from the website base URL when no override is saved. Confirm that the displayed addresses match your Node application. Older versions may require entering them manually. Passenger manages the application's listening endpoint, so use the HTTPS broadcast URL above for this setup rather than assuming it is available at 127.0.0.1:3001.
Click Test connection. Wait for a success result for both the internal service and the browser connection. Then click Save changes, reload the settings page, and confirm that the selected connection and URLs remain correct. A successful health check alone does not verify authenticated broadcasts or the browser connection.
7. Test chat between the trade participants
- Open an active trade as the buyer and seller in separate browser sessions.
- Send a message from each side and confirm that the other side receives it without refreshing the page.
- Check typing indicators and attachment delivery.
- Confirm that messages remain visible after reloading the trade page.
If the socket service is interrupted, the chat can fall back to HTTP polling. Use Test connection to verify Socket.IO separately, since messages arriving through polling do not prove that the socket connection works.
Troubleshooting the cPanel connection
| Result | What to check |
|---|---|
Cannot find module 'express' or 'socket.io' |
Run NPM Install for the socket-server application, then restart it. |
Missing APP_KEY |
Check that Node can read Laravel's .env and uses the same existing key. |
| PayMoney's Laravel 404 page at the health URL | Check the root .htaccess exception and cPanel's Passenger application mapping. |
Cannot GET /p2p-socket/health from Node |
Check Node returns Cannot GET below, then restart. |
| Passenger error page or HTTP 503 | Review the application log, startup file, dependencies, and hosting resource limits. |
| Health succeeds but the internal connection test fails | Check the broadcast URL, matching APP_KEY, Laravel's HTTPS access to its own domain, and whether the host's WAF permits the request and X-Internal-Secret header. |
| Browser connection test fails | Check HTTPS, WebSocket forwarding, the public URL, and the /p2p-socket/socket.io/ transport path. |
EADDRINUSE |
Check for a second manually started process and let the host confirm the application's listening configuration. |
Health URL shows PayMoney's Laravel 404 page
Laravel's rewrite rules may be intercepting the Node application URL. In File Manager, enable Settings > Show Hidden Files. Back up the domain root .htaccess, then add this exception inside its rewrite block, after the authorization-header rule and before the front-controller rules:
RewriteEngine On
# Preserve the existing authorization-header rule.
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Let cPanel Passenger handle the Node application URL.
RewriteRule ^p2p-socket(?:/|$) - [L]
# Keep the remaining website rules below this point.
Add the exception to the existing file and retain cPanel's generated Passenger configuration. Restart the Node application afterward and repeat the health check. If the request still reaches Laravel, ask your host to verify that Passenger maps /p2p-socket to the application root from step 2.
Node returns Cannot GET /p2p-socket/health
Some cPanel deployments forward the full /p2p-socket prefix to Node. If this error occurs, check Modules/P2PXchange/socket-server/server.js. The module version used for this setup includes the following Socket.IO path and route aliases.
Inside the existing new Server(server, { ... }) options, confirm this entry:
path: '/p2p-socket/socket.io/',
The health handler should accept both paths:
app.get(['/health', '/p2p-socket/health'], (_req, res) => {
res.json({ ok: true });
});
The broadcast route should begin with this declaration. Keep its complete existing handler body, including authentication:
app.post(['/internal/broadcast', '/p2p-socket/internal/broadcast'], (req, res) => {
If you have an older copy, back up server.js and update only the existing path and route declarations. Preserve the broadcast handler's secret check. Save, restart the Node application, and repeat the health check.
The browser and server must use matching Socket.IO transport paths, unless the host explicitly rewrites the path between them.
PayMoney's internal connection test fails
The real screenshot below shows an earlier default configuration and a failed test. It illustrates where the connection selector, URL fields, and test controls are located.

For this cPanel setup, enter https://example.com/p2p-socket as the public URL and https://example.com/p2p-socket/internal/broadcast as the internal URL, replacing example.com with your own domain. Repeat Test connection, then Save changes when both checks succeed. If it still fails, check the shared APP_KEY, Laravel's access to the HTTPS broadcast endpoint, and the host's WAF rules.
Socket.IO setup guide for VPS
PayMoney runs as a PHP/Laravel application. P2PXchange is an optional, on-demand module, so its files and settings may be absent from a normal installation. Within that module, Socket.IO is also optional: Node.js is needed only when you choose Socket.IO for P2P chat and trade updates.
| Your installation | What to set up |
|---|---|
| P2PXchange is not installed or enabled | Continue using the Laravel application. Skip this socket setup. |
| P2PXchange is enabled and uses Polling | P2P chat and trade updates use Laravel requests. No Node service or socket proxy is required. |
| P2PXchange is enabled and you want Socket.IO | Follow the steps below to add the module's optional Node relay. |
This guide applies to an Ubuntu/Debian VPS with systemd, where the Laravel website already works over HTTPS. It adds one P2P socket service on the same VPS as Laravel, with either Nginx or Apache forwarding the socket URL to it. PHP continues serving the application and P2P pages. Other Linux distributions use different package, firewall, and service commands.
All examples use example.com. Replace it with your domain, replace /var/www/example.com with the PayMoney directory containing artisan and .env, and replace DEPLOY_USER with an existing non-root Linux account that can read the application files and Laravel's .env.
1. Confirm that the P2P module is installed and enabled
Connect from your terminal using the SSH account and server address supplied by your provider:
ssh DEPLOY_USER@SERVER_IP
Open Admin > Addon Manager and confirm that P2PXchange is installed and enabled. If you have not installed it, complete the add-on's normal installation and activation process first. The socket setup does not install the P2P module, its PHP code, or its database tables.
Verify the files supplied by the installed module:
cd /var/www/example.com
ls Modules/P2PXchange/socket-server/server.js \
Modules/P2PXchange/socket-server/package.json \
Modules/P2PXchange/socket-server/package-lock.json
If those files are missing, stop here and check the module installation. Creating an empty socket-server directory will not supply the relay. Linux paths are case-sensitive; use the exact installed module directory name.
Keep Trade chat on Polling while preparing the service. Continue below only if you want Socket.IO. The core Laravel deployment and the P2P polling mode do not need this Node setup.
2. Prepare the optional Node runtime and socket dependencies
You need sudo access for the systemd service and web-server configuration. Confirm that the existing Laravel website works at https://example.com with a valid certificate, and identify which web server serves its HTTPS traffic. If Nginx sits in front of Apache, configure the socket route in the public-facing Nginx server block.
Check whether Node.js and npm are already available:
node --version
npm --version
command -v node
If either command is unavailable, install a supported Node.js LTS release and npm using the official Node.js installation instructions, then repeat the checks. If Node is already installed, confirm that its version is supported before using it. This runtime serves the optional P2P relay; PHP continues handling the website. Keep the absolute Node path returned by command -v node for step 3. Check the Node.js release status when choosing your runtime.
The bundled server listens on port 3001 by default and may listen on all network interfaces. Before starting it, use your provider's network firewall and the VPS's existing firewall to block external access to TCP 3001, while allowing local connections. Browsers will use the website's HTTPS port 443. Do not add a public allow rule for port 3001.
Install the Node dependencies inside the installed P2P module, as the account that owns the deployment files:
cd /var/www/example.com/Modules/P2PXchange/socket-server
ls server.js package.json package-lock.json
npm ci --omit=dev --workspaces=false
This installs only the socket package using its own lockfile. --workspaces=false keeps this installation independent of any workspace configuration in PayMoney's root package.json. No root-level npm workspace, P2P startup script, or frontend build is required for this procedure. If npm reports a manifest/lockfile mismatch, resolve it in the module release and redeploy the matching files.
Linux paths are case-sensitive. The commands use Modules/P2PXchange; use the exact installed directory name on your server.
The Node service discovers Laravel's .env in the parent application directory and uses its existing APP_KEY to authenticate broadcasts and socket tokens. Make sure DEPLOY_USER can read that file without making it publicly readable. Preserve the existing key, and check that an old socket-server/.env is not overriding it with a different key or port.
3. Create a service for the installed module's socket relay
Create a service file:
sudo nano /etc/systemd/system/paymoney-p2p.service
Add the following configuration. Replace DEPLOY_USER, all application paths, and /usr/bin/node with the values from your server. Use an absolute Node executable that this account can run; systemd does not load your interactive shell or activate a version manager automatically.
[Unit]
Description=PayMoney P2P Socket.IO relay
After=network.target
ConditionPathExists=/var/www/example.com/Modules/P2PXchange/socket-server/server.js
[Service]
Type=simple
User=DEPLOY_USER
WorkingDirectory=/var/www/example.com/Modules/P2PXchange/socket-server
ExecStart=/usr/bin/node /var/www/example.com/Modules/P2PXchange/socket-server/server.js --port=3001
Environment=NODE_ENV=production
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Save the file, then load and start the service:
sudo systemctl daemon-reload
sudo systemctl enable --now paymoney-p2p
sudo systemctl status paymoney-p2p --no-pager
curl --fail http://127.0.0.1:3001/health
The service should be active (running) and the health request should return {"ok":true}. Enabling the service starts it automatically after reboot; Restart=on-failure restarts it after an unexpected failure. See the systemd service documentation for those controls.
Replace the application path in ConditionPathExists along with the other paths. This systemd path condition skips startup if the module's server file is absent. It checks file presence, not Laravel's module activation status: stop and disable the service using step 8 before disabling or removing P2PXchange. Installing or activating the add-on does not create or manage this systemd unit automatically.
Run one instance of this relay. If you previously started it manually or through PM2, stop that instance before enabling this systemd service. Rooms are stored in memory, so multiple independent processes can cause missing updates.
4. Forward HTTPS traffic to Node
Follow one of the web-server options below, using the server that receives requests for example.com. Keep the website's existing TLS, document-root, and PHP configuration. Back up the existing site configuration before editing it.
Add only the P2P socket and health routes shown below. The existing Laravel routes continue through the site's PHP handler; the Node service handles the module's socket transport.
Option A: Nginx
Open the site's active configuration, commonly under /etc/nginx/sites-available/. Add these locations inside the existing HTTPS server {} block for example.com:
location ^~ /p2p-socket/socket.io/ {
proxy_pass http://127.0.0.1:3001/p2p-socket/socket.io/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 75s;
proxy_send_timeout 75s;
proxy_buffering off;
}
location = /p2p-socket/health {
proxy_pass http://127.0.0.1:3001/health;
proxy_set_header Host $host;
}
The first location forwards both HTTP polling and WebSocket upgrades. The health location allows a public reachability check. Laravel will send authenticated broadcasts directly to loopback, so this configuration does not need a public broadcast route.
Validate the configuration, and reload only if the check succeeds:
sudo nginx -t
sudo systemctl reload nginx
Nginx does not read .htaccess. The Nginx WebSocket documentation explains the upgrade headers; the Socket.IO reverse-proxy guide explains the timeout requirements.
Option B: Apache
Use Apache 2.4.47 or newer for the WebSocket forwarding syntax below. Check the version and enable the required modules:
apache2 -v
sudo a2enmod proxy proxy_http headers
Open the site's active HTTPS VirtualHost configuration, commonly under /etc/apache2/sites-available/. Add these directives inside the existing <VirtualHost *:443>, before any broader ProxyPass rule:
ProxyPass "/p2p-socket/socket.io/" "http://127.0.0.1:3001/p2p-socket/socket.io/" upgrade=websocket timeout=75
ProxyPassReverse "/p2p-socket/socket.io/" "http://127.0.0.1:3001/p2p-socket/socket.io/"
ProxyPass "/p2p-socket/health" "http://127.0.0.1:3001/health"
ProxyPassReverse "/p2p-socket/health" "http://127.0.0.1:3001/health"
Validate the configuration, and reload only if it reports Syntax OK:
sudo apache2ctl configtest
sudo systemctl reload apache2
These proxy directives belong in the VirtualHost configuration. The cPanel Passenger exception alone does not configure a VPS reverse proxy. See the Apache proxy documentation for the required proxy modules.
If PayMoney is installed under a URL subdirectory
For a website at https://example.com/paymoney, use /paymoney/p2p-socket/socket.io/ and /paymoney/p2p-socket/health on the public side of the proxy rules above. Keep the Node upstream paths as /p2p-socket/socket.io/ and /health. Use https://example.com/paymoney/p2p-socket as the public socket URL in step 6. The filesystem directory and public URL path are separate settings.
5. Allow browser connections and verify the proxy
If the website sends a Content Security Policy, its connect-src directive must permit the website's HTTP requests and secure WebSocket connections. For this same-domain HTTPS setup, the required sources are:
'self' wss://example.com
Merge those sources into the existing connect-src directive, retaining any other sources and policy directives. Update the policy where it is actually sent: Nginx's site configuration, Apache's VirtualHost, the application's .htaccess, or another configured layer. Adding a second policy does not override a restrictive policy already present. Reload the affected web server after validating its configuration.
From your terminal, check the public health and transport addresses:
curl --fail https://example.com/p2p-socket/health
curl --fail 'https://example.com/p2p-socket/socket.io/?EIO=4&transport=polling'
The health response should be {"ok":true}. The transport response should begin with 0{ followed by connection information. Use the installation prefix in both URLs if PayMoney runs under a subdirectory. These checks confirm reachability and polling transport; the admin connection test checks authentication and browser connectivity next.
6. Configure and test PayMoney
Make sure Laravel's APP_URL is the full public website URL, such as https://example.com or https://example.com/paymoney. If you change .env, clear cached configuration from the PayMoney directory, then rebuild it if your deployment normally uses configuration caching:
cd /var/www/example.com
php artisan config:clear
Open Admin > P2P Exchange > Settings > Trade chat and set:
| Field | Value for this VPS setup |
|---|---|
| Chat connection | Socket.IO — instant updates. |
| Public socket URL | https://example.com/p2p-socket |
| Internal broadcast URL | http://127.0.0.1:3001/internal/broadcast |
Save the internal URL as the explicit loopback address above. It is a custom override for this same-VPS deployment; the automatic domain-based broadcast URL would need its own proxy route. Never enter 127.0.0.1 as the public URL for remote visitors: their browser would try to connect to their own computer.
Select Socket.IO in the form, click Test connection, and wait for both the internal and browser checks to succeed before clicking Save changes. If either check fails, keep the saved mode on Polling while troubleshooting. Saving this setting does not install Node dependencies or start the systemd service.
Reload the settings page and confirm the values persist. Open an active trade as its two participants in separate browser sessions, and test messages, typing indicators, and attachments without refreshing the page. Messages should remain visible after a reload.
7. View logs and restart after updates
Use these commands for routine operation:
| Task | Command |
|---|---|
| Check service status | sudo systemctl status paymoney-p2p --no-pager |
| Show recent service logs | sudo journalctl -u paymoney-p2p -n 100 --no-pager |
| Follow service logs | sudo journalctl -u paymoney-p2p -f |
| Restart after a server-code or key change | sudo systemctl restart paymoney-p2p |
| Confirm startup is enabled | sudo systemctl is-enabled paymoney-p2p |
Run these socket maintenance commands only while P2PXchange is installed, enabled, and configured for Socket.IO. After updating the module's server.js or dependencies, install its release dependencies using step 2, restart the service, and repeat the health and admin connection checks. A PHP-only update does not require reinstalling socket dependencies unless the module's socket package also changed.
When deploying a new Laravel release, make sure your deployment process carries the installed on-demand module into that release and that the service paths point to its actual location. If you edit the systemd unit, run sudo systemctl daemon-reload before restarting. Reboot verification can be performed during your normal server maintenance window.
8. Switch to polling or disable the P2P module
Before returning to polling, disabling P2PXchange, or removing its files:
- While the module is still enabled, open Admin > P2P Exchange > Settings, select Polling, and save. Confirm P2P chat works through Laravel if you intend to keep using the module.
- Stop the optional relay and disable its automatic startup:
sudo systemctl disable --now paymoney-p2p
- Remove the P2P-specific socket and health proxy rules from the website configuration. Validate and reload the web server using the matching commands in step 4. Retain the website's PHP, TLS, and other routing configuration.
- If you intend to disable or remove P2PXchange, continue with the add-on's normal management process after the socket service is stopped. If the module was already removed, skip its unavailable settings screen and perform the service and proxy cleanup directly.
Node.js may also be used by other applications or build tools on the VPS. Disabling this optional relay does not require uninstalling the shared Node runtime.
To enable Socket.IO again later, install and enable P2PXchange first, check its files and dependencies, then restore the service and proxy configuration and repeat the connection tests. If a module update changes the installation path, update the systemd paths before starting it.
Troubleshooting the VPS connection
| Result | What to check |
|---|---|
P2P settings or socket-server files are missing |
Confirm P2PXchange is installed and enabled. Skip socket setup for deployments without the module. |
| systemd skips the service because its path condition fails | The module's server.js is absent or ConditionPathExists uses the wrong case or deployment path. Install the module before enabling the relay. |
node or npm is missing |
Install a supported Node.js LTS runtime and npm; verify both commands as the deployment account. |
Service fails with 203/EXEC |
Check the absolute Node executable in ExecStart and whether DEPLOY_USER can execute it. |
Missing APP_KEY or HTTP 403 on authenticated broadcasts |
Check that Node can read the same Laravel .env, that a local socket .env does not override the key, and restart Node after a key change. |
EADDRINUSE |
Check for an existing relay on port 3001. Use one process manager for this service. |
| Public health returns HTTP 502 or 503 | Check systemd status, the loopback health URL, the configured upstream port, and the web-server error log. |
| Public health returns a Laravel 404 | Check that the proxy rules are in the active HTTPS site and include the correct installation prefix. |
| Health works but the transport URL returns 404 | Confirm the proxy forwards to Node's /p2p-socket/socket.io/ path; older module versions need the prefix support described in the cPanel troubleshooting section. |
| Internal test succeeds but browser test fails | Check the browser console for CSP or mixed-content errors, the public HTTPS URL, and WebSocket upgrade forwarding. |
| Messages arrive only after a delay | Polling may be active. Repeat the admin test and check the proxy and Node logs. |
P2P marketplace on the front end (guest)
Visitors open the P2P exchange page from the site menu. They see active buy offers by default, along with FAQs, fiat gateway badges, filters (asset, fiat, payment time, region), and sorting.

- Clicking an offer opens detail and an initiate flow. Login is required to start a trade; guests are redirected to login and can return afterward.

-
The platform blocks self-trading (you cannot take your own advertisement).
-
After a successful initiate exchange, the user is sent into the user panel trade flow (prepare step, then the live trade room).
Offer creator profile on the front end (guest)
From the P2P marketplace, visitors can open the advertiser profile (also called offer creator profile) for the user who published that advertisement. The public URL lives under the same P2P exchange section.

-
The profile summarizes trust signals for that trader: counts of total and active offers, overall and recent trade volume, and a completion rate over a recent window so you can see how reliably they finish trades.
-
You can also see how their activity splits between buy-type and sell-type exchanges (as the advertiser), and when their first trade on the platform occurred, where the theme exposes these fields.
-
Use this page to compare advertisers before you click initiate; it does not replace reading the offer’s price, limits, and payment instructions on the listing itself.
-
This page also show all the feedback this creator got for the exchanges he has done.

Create and edit P2P offers from the user panel
Users who pass KYC and offer creator checks (when your site enables those middlewares) can open P2P offers in the user area. Creation and editing use a three-step wizard (pricing and limits, payment instructions, final details such as auto-reply text for chat).

- Step one usually covers type (buy/sell), currencies, price or margin, min/max amounts, and timing.

- Step two links fiat gateways to human-readable instructions (account number, wallet ID, bank branch, etc.).

- Step three finishes legal or marketing fields and auto-reply; the advertiser can delete an offer where the business rules allow it.

P2P transactions list for the user
Logged-in users open P2P transactions from the user menu. They can switch ongoing and completed lists, filter by date range, type, asset, or fiat, and open a trade or print a related wallet transaction PDF when available.

-
From ongoing, each row leads to the trade workflow (via detail information then detail).
-
A dispute shortcut finds the correct wallet lines; if a dispute already exists, the user is sent to the discussion thread, otherwise to create dispute.
Complete a trade in the user panel
When a trade is pending, the counterparty may cancel (reject) if the product allows it. After the trade is active, the buyer follows payment instructions, then uses I have paid to upload one to five proof files (images or PDF) and an optional note. The seller verifies proof, then uses confirm / release so crypto moves according to fee settings and the trade becomes completed.

-
Offer creator and exchanger see different layouts (buy-detail vs sell-detail) but the same underlying status and timers.
-
Automated chat lines can appear when the trade starts (including optional auto-reply from the advertiser), when someone marks paid, cancels, or releases crypto.
-
After completion, the exchanger may leave one feedback entry about the experience.
Trade detail and in-trade chat in the user panel
Inside the trade page, chat is visible only to the two participants. They can send text and up to five attachments per message (common types: JPEG, PNG, GIF, WebP, PDF). Chat closes when the trade is completed or expired.

-
Messages are always stored in the database; the page polls for updates on a fixed interval (for example every few seconds).
-
When Socket.IO is enabled, new messages appear immediately, typing indicators can show, and the trade UI can refresh fragments.
Open a P2P dispute from the user panel
If payment or release fails, the user opens P2P disputes, chooses create from the guided entry point, and submits reason and evidence as your form requires. Ongoing discussion uses the same dispute module as the rest of Paymoney.
